#hashset #query #search #database


partial queries in HashSets, the traits

3 releases

✓ Uses Rust 2018 edition

0.1.2 Dec 23, 2018
0.1.1 Dec 21, 2018
0.1.0 Dec 21, 2018

#374 in Data structures

25 downloads per month
Used in 2 crates

MIT license



Smart Hash is a collection of traits that allows you to use a HashSet with a struct of your design to make quick and easy queries.

What is it?

smart-hash adds a trait which makes it easy to search for partial matches inside of a HashSet. Think of it as querying your HashSet for matching data.


  • Only can match on equality (no lt, gt, etc ...)

Minimum Example

A quick 'get it working' example to show what it does, and how to set it up. (Using new rust 2018)

extern crate smart_hash;
use smart_hash::{get_matching,SmartHash}; // macros
use smart_hash::traits::SmartHashSet;

#[derive(SmartHash, Hash, Eq, PartialEq)]
pub struct Person {
    name : String,
    age : u8,
    height: u8,

pub fn main() {
    let people : HashSet<Person> = HashSet::New();
    // do something here to add a bunch of people into it....
    // not using the macro access method (same result as below)
    let people_25 = people.get_matching(PeopleOpt{
        name : None,
        age : Some(25),
        height : None,

    // using the macro access method (same result as above)
    let people_25 = get_matching!(people,age == 25);

    // looks at the results
    if let Some(people) in people_25 {
        for p in people {
            // should only print out the people who are 25 (where age == 25)


smart-hash has a few features, but probably does what you want by default. (Meaning you don't need to do anything)

  • default - includes all macros in scope, including derive.
  • derive - same as the default.
  • manual - does not include the derive macro, assumes you will implement everything yourself.

Whats Included?


The smart-hash crate includes the following public traits.


The SmartHash trait makes the struct for partial matching. It requires a second struct to exist (the option) and a function into_option to create a option struct with the values in the original struct.

Assume your data structure looks like this.

pub Struct Car {
    color : Color,
    make : String,
    year : Date,

In order to implement SmartHash you would need to add the following.

NOTE: all this is automatically done for you if you use #[derive(SmartHash)] from smart-hash-derive.

// the options struct
pub Struct CarOpt {
    color : Option<Color>,
    make : Option<String>,
    year : Option<Date>,

// SmartHash requires Default to be implemented
impl Default for CarOpt {
    fn default() -> CarOpt {
        CarOpt { 
            color: None, 
            make: None, 

// implement SmartHash
impl SmartHash for Car {
    type option = CarOpt;

    fn into_option(&self) -> CarOpt {
        CarOpt {
            color: Some(self.color),
            make : Some(self.make),
            year : Some(self.year),

The new option struct needs some empty traits implemented aswell..

NOTE: all this is automatically done for you if you use #[derive(SmartHash)] from smart-hash-derive.

impl SmartHashOpt for CarOpt { }

// allows the partial matching
impl Eq for CarOpt {}
impl PartialEq for CarOpt {
    fn eq(&self, other: &CarOpt) -> bool {
        (self.color == other.color || self.color.is_none() || other.color.is_none()) &&
        (self.make == other.make || self.make.is_none() || other.make.is_none()) &&
        (self.year == other.year || self.year.is_none() || other.year.is_none())


A trait that has a default implementation for all structs that implement SmartHash that are inside a HashSet. This adds an additional function to the HashSet do you can do fuzzy searches / partial queries.

// in our example, the signature looks like this
fn get_matching<'a>(&'a self : HashSet<Car>, query : CarOpt) -> Option<Vec<&'a Car>>
get_matching!() Macro

A macro is also included to make searching easier and cleaner. Once you mark the extern with #[macro_use] you can then use the following macro.

// basic signature descriptions
macro get_matching!(object, key, value, k2, v2, ...) -> Option<Vec<object_member>>;
macro get_matching!(object, key == value, k2 == v2, ...) -> Option<Vec<object_member>>;
macro get_matching!(object where key is value, k2 is v2, ...) -> Option<Vec<object_member>>;
derive Macro

The derive macro from smart-hash-derive is exposed in the smart-hash create so you don't have to do anything additional.


Crate including the procedural macro. There is nothing to do here except #[macro_use] the extern and then use the macro. You do not need to use this if you are using Rust 2018 because it is already included in the base smart-hash crate. All previous version will need to use it to get the derive macro.

NOTE: the other derives, Hash, Eq, PartialEq are requirements for HashSet and required as well.

#[derive(Hash, Eq, PartialEq, SmartHash)]
pub struct Person {
    name : String,
    age : u8,
    country : String,



The smart-hash crate has everything you need, but makes it complicated. You'll have to implement a lot. You can look at the test to see what needs to be written. Most of it is boiler plate and copy and paste. I'd recommend using the derive macro.


The smart-hash-derive crate is a procedural macro that will derive SmartHash and its children traits automatically so you don't have to worry about a thing.


A standalone binary app to test the macro scoping and make sure everything is accessable as planned.


  • Allow for all comparision operators in the macro: lt, gt, <=, >=, <>, etc ....


~28K SLoC