Struct TriHashMap

Source
pub struct TriHashMap<T: TriHashItem, S = DefaultHashBuilder, A: Allocator = Global> { /* private fields */ }
Expand description

A 1:1:1 (trijective) map for three keys and a value.

The storage mechanism is a fast hash table of integer indexes to items, with these indexes stored in three hashmaps. This allows for efficient lookups by any of the three keys, while preventing duplicates.

§Examples

use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

// Implement TriHashItem to define the three key types.
impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }

    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }

    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }

    tri_upcast!();
}

// Create a TriHashMap and insert items.
let mut people = TriHashMap::new();
people
    .insert_unique(Person {
        id: 1,
        email: "alice@example.com".to_string(),
        phone: "555-1234".to_string(),
        name: "Alice".to_string(),
    })
    .unwrap();

// Lookup by any of the three keys.
let person = people.get1(&1).unwrap();
assert_eq!(person.name, "Alice");

let person = people.get2("alice@example.com").unwrap();
assert_eq!(person.id, 1);

let person = people.get3("555-1234").unwrap();
assert_eq!(person.email, "alice@example.com");

Implementations§

Source§

impl<T: TriHashItem> TriHashMap<T>

Source

pub fn new() -> Self

Creates a new, empty TriHashMap.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let map: TriHashMap<Person> = TriHashMap::new();
assert!(map.is_empty());
assert_eq!(map.len(), 0);
Source

pub fn with_capacity(capacity: usize) -> Self

Creates a new TriHashMap with the given capacity.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let map: TriHashMap<Person> = TriHashMap::with_capacity(10);
assert!(map.capacity() >= 10);
assert!(map.is_empty());
Source§

impl<T: TriHashItem, S: Clone + BuildHasher> TriHashMap<T, S>

Source

pub fn with_hasher(hasher: S) -> Self

Creates a new, empty TriHashMap with the given hasher.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};
use std::collections::hash_map::RandomState;

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let map: TriHashMap<Person, RandomState> =
    TriHashMap::with_hasher(RandomState::new());
assert!(map.is_empty());
Source

pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self

Creates a new TriHashMap with the given capacity and hasher.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};
use std::collections::hash_map::RandomState;

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let map: TriHashMap<Person, RandomState> =
    TriHashMap::with_capacity_and_hasher(10, RandomState::new());
assert!(map.capacity() >= 10);
assert!(map.is_empty());
Source§

impl<T: TriHashItem, A: Clone + Allocator> TriHashMap<T, DefaultHashBuilder, A>

Source

pub fn new_in(alloc: A) -> Self

Creates a new empty TriHashMap using the given allocator.

Requires the allocator-api2 feature to be enabled.

§Examples

Using the bumpalo allocator:

use iddqd::{TriHashMap, TriHashItem, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

// Define a new allocator.
let bump = bumpalo::Bump::new();
// Create a new TriHashMap using the allocator.
let map: TriHashMap<Person, _, &bumpalo::Bump> = TriHashMap::new_in(&bump);
assert!(map.is_empty());
Source

pub fn with_capacity_in(capacity: usize, alloc: A) -> Self

Creates an empty TriHashMap with the specified capacity using the given allocator.

Requires the allocator-api2 feature to be enabled.

§Examples

Using the bumpalo allocator:

use iddqd::{TriHashMap, TriHashItem, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

// Define a new allocator.
let bump = bumpalo::Bump::new();
// Create a new TriHashMap with capacity using the allocator.
let map: TriHashMap<Person, _, &bumpalo::Bump> = TriHashMap::with_capacity_in(10, &bump);
assert!(map.capacity() >= 10);
assert!(map.is_empty());
Source§

impl<T: TriHashItem, S: Clone + BuildHasher, A: Clone + Allocator> TriHashMap<T, S, A>

Source

pub fn with_hasher_in(hasher: S, alloc: A) -> Self

Creates a new, empty TriHashMap with the given hasher and allocator.

Requires the allocator-api2 feature to be enabled.

§Examples

Using the bumpalo allocator:

use iddqd::{TriHashItem, TriHashMap, tri_upcast};
use std::collections::hash_map::RandomState;

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

// Define a new allocator.
let bump = bumpalo::Bump::new();
let hasher = RandomState::new();
// Create a new TriHashMap with hasher using the allocator.
let map: TriHashMap<Person, _, &bumpalo::Bump> =
    TriHashMap::with_hasher_in(hasher, &bump);
assert!(map.is_empty());
Source

pub fn with_capacity_and_hasher_in(capacity: usize, hasher: S, alloc: A) -> Self

Creates a new TriHashMap with the given capacity, hasher, and allocator.

Requires the allocator-api2 feature to be enabled.

§Examples

Using the bumpalo allocator:

use iddqd::{TriHashItem, TriHashMap, tri_upcast};
use std::collections::hash_map::RandomState;

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

// Define a new allocator.
let bump = bumpalo::Bump::new();
let hasher = RandomState::new();
// Create a new TriHashMap with capacity and hasher using the allocator.
let map: TriHashMap<Person, _, &bumpalo::Bump> =
    TriHashMap::with_capacity_and_hasher_in(10, hasher, &bump);
assert!(map.capacity() >= 10);
assert!(map.is_empty());
Source§

impl<T: TriHashItem, S: Clone + BuildHasher, A: Allocator> TriHashMap<T, S, A>

Source

pub fn allocator(&self) -> &A

Returns the allocator.

Requires the allocator-api2 feature to be enabled.

§Examples

Using the bumpalo allocator:

use iddqd::{TriHashMap, TriHashItem, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

// Define a new allocator.
let bump = bumpalo::Bump::new();
// Create a new TriHashMap using the allocator.
let map: TriHashMap<Person, _, &bumpalo::Bump> = TriHashMap::new_in(&bump);
// Access the allocator.
let allocator = map.allocator();
Source

pub fn capacity(&self) -> usize

Returns the currently allocated capacity of the map.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let map: TriHashMap<Person> = TriHashMap::with_capacity(10);
assert!(map.capacity() >= 10);
Source

pub fn is_empty(&self) -> bool

Returns true if the map is empty.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
assert!(map.is_empty());

map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();
assert!(!map.is_empty());
Source

pub fn len(&self) -> usize

Returns the number of items in the map.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
assert_eq!(map.len(), 0);

map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();
map.insert_unique(Person {
    id: 2,
    email: "bob@example.com".to_string(),
    phone: "555-5678".to_string(),
    name: "Bob".to_string(),
})
.unwrap();
assert_eq!(map.len(), 2);
Source

pub fn iter(&self) -> Iter<'_, T>

Iterates over the items in the map.

Similar to HashMap, the iteration order is arbitrary and not guaranteed to be stable.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();
map.insert_unique(Person {
    id: 2,
    email: "bob@example.com".to_string(),
    phone: "555-5678".to_string(),
    name: "Bob".to_string(),
})
.unwrap();

let mut count = 0;
for person in map.iter() {
    assert!(person.id == 1 || person.id == 2);
    count += 1;
}
assert_eq!(count, 2);
Source

pub fn iter_mut(&mut self) -> IterMut<'_, T, S, A>

Iterates over the items in the map, allowing for mutation.

Similar to HashMap, the iteration order is arbitrary and not guaranteed to be stable.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();

for mut person in map.iter_mut() {
    person.name.push_str(" Updated");
}

let person = map.get1(&1).unwrap();
assert_eq!(person.name, "Alice Updated");
Source

pub fn insert_overwrite(&mut self, value: T) -> Vec<T>

Inserts a value into the map, removing any conflicting items and returning a list of those items.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();

// First insertion - no conflicts
let overwritten = map.insert_overwrite(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
});
assert!(overwritten.is_empty());

// Overwrite with same id - returns the old item
let overwritten = map.insert_overwrite(Person {
    id: 1,
    email: "alice.new@example.com".to_string(),
    phone: "555-9999".to_string(),
    name: "Alice New".to_string(),
});
assert_eq!(overwritten.len(), 1);
assert_eq!(overwritten[0].name, "Alice");
Source

pub fn insert_unique(&mut self, value: T) -> Result<(), DuplicateItem<T, &T>>

Inserts a value into the set, returning an error if any duplicates were added.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();

// Successful insertion
assert!(
    map.insert_unique(Person {
        id: 1,
        email: "alice@example.com".to_string(),
        phone: "555-1234".to_string(),
        name: "Alice".to_string(),
    })
    .is_ok()
);
assert!(
    map.insert_unique(Person {
        id: 2,
        email: "bob@example.com".to_string(),
        phone: "555-5678".to_string(),
        name: "Bob".to_string(),
    })
    .is_ok()
);

// Duplicate key1
assert!(
    map.insert_unique(Person {
        id: 1,
        email: "charlie@example.com".to_string(),
        phone: "555-9999".to_string(),
        name: "Charlie".to_string(),
    })
    .is_err()
);

// Duplicate key2
assert!(
    map.insert_unique(Person {
        id: 3,
        email: "alice@example.com".to_string(),
        phone: "555-7777".to_string(),
        name: "Alice2".to_string(),
    })
    .is_err()
);

// Duplicate key3
assert!(
    map.insert_unique(Person {
        id: 4,
        email: "dave@example.com".to_string(),
        phone: "555-1234".to_string(),
        name: "Dave".to_string(),
    })
    .is_err()
);
Source

pub fn contains_key_unique<'a, Q1, Q2, Q3>( &'a self, key1: &Q1, key2: &Q2, key3: &Q3, ) -> bool
where Q1: Hash + Equivalent<T::K1<'a>> + ?Sized, Q2: Hash + Equivalent<T::K2<'a>> + ?Sized, Q3: Hash + Equivalent<T::K3<'a>> + ?Sized,

Returns true if the map contains a single item that matches all three keys.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
}).unwrap();
map.insert_unique(Person {
    id: 2,
    email: "bob@example.com".to_string(),
    phone: "555-5678".to_string(),
    name: "Bob".to_string(),
}).unwrap();

assert!(map.contains_key_unique(&1, &"alice@example.com", &"555-1234"));
assert!(map.contains_key_unique(&2, &"bob@example.com", &"555-5678"));
assert!(!map.contains_key_unique(&1, &"bob@example.com", &"555-1234")); // key1 exists but key2 doesn't match
assert!(!map.contains_key_unique(&3, &"charlie@example.com", &"555-9999")); // none of the keys exist
Source

pub fn get_unique<'a, Q1, Q2, Q3>( &'a self, key1: &Q1, key2: &Q2, key3: &Q3, ) -> Option<&'a T>
where Q1: Hash + Equivalent<T::K1<'a>> + ?Sized, Q2: Hash + Equivalent<T::K2<'a>> + ?Sized, Q3: Hash + Equivalent<T::K3<'a>> + ?Sized,

Gets a reference to the unique item associated with the given key1, key2, and key3, if it exists.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();

// All three keys must match
assert_eq!(
    map.get_unique(&1, &"alice@example.com", &"555-1234").unwrap().name,
    "Alice"
);

// If any key doesn't match, returns None
assert!(map.get_unique(&1, &"wrong@example.com", &"555-1234").is_none());
assert!(map.get_unique(&2, &"alice@example.com", &"555-1234").is_none());
Source

pub fn get_mut_unique<'a, Q1, Q2, Q3>( &'a mut self, key1: &Q1, key2: &Q2, key3: &Q3, ) -> Option<RefMut<'a, T, S>>
where Q1: Hash + Equivalent<T::K1<'a>> + ?Sized, Q2: Hash + Equivalent<T::K2<'a>> + ?Sized, Q3: Hash + Equivalent<T::K3<'a>> + ?Sized,

Gets a mutable reference to the unique item associated with the given key1, key2, and key3, if it exists.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();

// Modify the item through the mutable reference
if let Some(mut person) =
    map.get_mut_unique(&1, &"alice@example.com", &"555-1234")
{
    person.name = "Alice Updated".to_string();
}

// Verify the change
assert_eq!(map.get1(&1).unwrap().name, "Alice Updated");
Source

pub fn remove_unique<'a, Q1, Q2, Q3>( &'a mut self, key1: &Q1, key2: &Q2, key3: &Q3, ) -> Option<T>
where Q1: Hash + Equivalent<T::K1<'a>> + ?Sized, Q2: Hash + Equivalent<T::K2<'a>> + ?Sized, Q3: Hash + Equivalent<T::K3<'a>> + ?Sized,

Removes the item uniquely identified by key1, key2, and key3, if it exists.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();

// Remove the item using all three keys
let removed = map.remove_unique(&1, &"alice@example.com", &"555-1234");
assert!(removed.is_some());
assert_eq!(removed.unwrap().name, "Alice");

// Map is now empty
assert!(map.is_empty());

// Trying to remove again returns None
assert!(map.remove_unique(&1, &"alice@example.com", &"555-1234").is_none());
Source

pub fn contains_key1<'a, Q>(&'a self, key1: &Q) -> bool
where Q: Hash + Equivalent<T::K1<'a>> + ?Sized,

Returns true if the map contains the given key1.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();

assert!(map.contains_key1(&1));
assert!(!map.contains_key1(&2));
Source

pub fn get1<'a, Q>(&'a self, key1: &Q) -> Option<&'a T>
where Q: Hash + Equivalent<T::K1<'a>> + ?Sized,

Gets a reference to the value associated with the given key1.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();

assert_eq!(map.get1(&1).unwrap().name, "Alice");
assert!(map.get1(&2).is_none());
Source

pub fn get1_mut<'a, Q>(&'a mut self, key1: &Q) -> Option<RefMut<'a, T, S>>
where Q: Hash + Equivalent<T::K1<'a>> + ?Sized,

Gets a mutable reference to the value associated with the given key1.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();

if let Some(mut person) = map.get1_mut(&1) {
    person.name = "Alice Updated".to_string();
}

assert_eq!(map.get1(&1).unwrap().name, "Alice Updated");
Source

pub fn remove1<'a, Q>(&'a mut self, key1: &Q) -> Option<T>
where Q: Hash + Equivalent<T::K1<'a>> + ?Sized,

Removes an item from the map by its key1.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();

let removed = map.remove1(&1);
assert!(removed.is_some());
assert_eq!(removed.unwrap().name, "Alice");
assert!(map.is_empty());
Source

pub fn contains_key2<'a, Q>(&'a self, key2: &Q) -> bool
where Q: Hash + Equivalent<T::K2<'a>> + ?Sized,

Returns true if the map contains the given key2.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();

assert!(map.contains_key2("alice@example.com"));
assert!(!map.contains_key2("bob@example.com"));
Source

pub fn get2<'a, Q>(&'a self, key2: &Q) -> Option<&'a T>
where Q: Hash + Equivalent<T::K2<'a>> + ?Sized,

Gets a reference to the value associated with the given key2.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();

assert_eq!(map.get2("alice@example.com").unwrap().name, "Alice");
assert!(map.get2("bob@example.com").is_none());
Source

pub fn get2_mut<'a, Q>(&'a mut self, key2: &Q) -> Option<RefMut<'a, T, S>>
where Q: Hash + Equivalent<T::K2<'a>> + ?Sized,

Gets a mutable reference to the value associated with the given key2.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();

if let Some(mut person) = map.get2_mut("alice@example.com") {
    person.name = "Alice Updated".to_string();
}

assert_eq!(map.get2("alice@example.com").unwrap().name, "Alice Updated");
Source

pub fn remove2<'a, Q>(&'a mut self, key2: &Q) -> Option<T>
where Q: Hash + Equivalent<T::K2<'a>> + ?Sized,

Removes an item from the map by its key2.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();

let removed = map.remove2("alice@example.com");
assert!(removed.is_some());
assert_eq!(removed.unwrap().name, "Alice");
assert!(map.is_empty());
Source

pub fn contains_key3<'a, Q>(&'a self, key3: &Q) -> bool
where Q: Hash + Equivalent<T::K3<'a>> + ?Sized,

Returns true if the map contains the given key3.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();

assert!(map.contains_key3("555-1234"));
assert!(!map.contains_key3("555-5678"));
Source

pub fn get3<'a, Q>(&'a self, key3: &Q) -> Option<&'a T>
where Q: Hash + Equivalent<T::K3<'a>> + ?Sized,

Gets a reference to the value associated with the given key3.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();

assert_eq!(map.get3("555-1234").unwrap().name, "Alice");
assert!(map.get3("555-5678").is_none());
Source

pub fn get3_mut<'a, Q>(&'a mut self, key3: &Q) -> Option<RefMut<'a, T, S>>
where Q: Hash + Equivalent<T::K3<'a>> + ?Sized,

Gets a mutable reference to the value associated with the given key3.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();

if let Some(mut person) = map.get3_mut("555-1234") {
    person.name = "Alice Updated".to_string();
}

assert_eq!(map.get3("555-1234").unwrap().name, "Alice Updated");
Source

pub fn remove3<'a, Q>(&'a mut self, key3: &Q) -> Option<T>
where Q: Hash + Equivalent<T::K3<'a>> + ?Sized,

Removes an item from the map by its key3.

§Examples
use iddqd::{TriHashItem, TriHashMap, tri_upcast};

#[derive(Debug, PartialEq, Eq)]
struct Person {
    id: u32,
    email: String,
    phone: String,
    name: String,
}

impl TriHashItem for Person {
    type K1<'a> = u32;
    type K2<'a> = &'a str;
    type K3<'a> = &'a str;

    fn key1(&self) -> Self::K1<'_> {
        self.id
    }
    fn key2(&self) -> Self::K2<'_> {
        &self.email
    }
    fn key3(&self) -> Self::K3<'_> {
        &self.phone
    }
    tri_upcast!();
}

let mut map = TriHashMap::new();
map.insert_unique(Person {
    id: 1,
    email: "alice@example.com".to_string(),
    phone: "555-1234".to_string(),
    name: "Alice".to_string(),
})
.unwrap();

let removed = map.remove3("555-1234");
assert!(removed.is_some());
assert_eq!(removed.unwrap().name, "Alice");
assert!(map.is_empty());

Trait Implementations§

Source§

impl<T: Clone + TriHashItem, S: Clone, A: Clone + Allocator> Clone for TriHashMap<T, S, A>

Source§

fn clone(&self) -> TriHashMap<T, S, A>

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<'a, T, S, A: Allocator> Debug for TriHashMap<T, S, A>
where T: TriHashItem + Debug + 'a, T::K1<'a>: Debug, T::K2<'a>: Debug, T::K3<'a>: Debug,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T: TriHashItem, S: Default, A: Allocator + Default> Default for TriHashMap<T, S, A>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<T: TriHashItem, S: Clone + BuildHasher, A: Allocator> Extend<T> for TriHashMap<T, S, A>

The Extend implementation overwrites duplicates. In the future, there will also be an extend_unique method that will return an error.

Source§

fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I)

Extends a collection with the contents of an iterator. Read more
Source§

fn extend_one(&mut self, item: A)

🔬This is a nightly-only experimental API. (extend_one)
Extends a collection with exactly one element.
Source§

fn extend_reserve(&mut self, additional: usize)

🔬This is a nightly-only experimental API. (extend_one)
Reserves capacity in a collection for the given number of additional elements. Read more
Source§

impl<T: TriHashItem, S: Default + Clone + BuildHasher, A: Default + Allocator> FromIterator<T> for TriHashMap<T, S, A>

The FromIterator implementation for TriHashMap overwrites duplicate items.

Source§

fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self

Creates a value from an iterator. Read more
Source§

impl<'a, T: TriHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator for &'a TriHashMap<T, S, A>

Source§

type Item = &'a T

The type of the elements being iterated over.
Source§

type IntoIter = Iter<'a, T>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<'a, T: TriHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator for &'a mut TriHashMap<T, S, A>

Source§

type Item = RefMut<'a, T, S>

The type of the elements being iterated over.
Source§

type IntoIter = IterMut<'a, T, S, A>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<T: TriHashItem, S: Clone + BuildHasher, A: Allocator> IntoIterator for TriHashMap<T, S, A>

Source§

type Item = T

The type of the elements being iterated over.
Source§

type IntoIter = IntoIter<T, A>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<T: TriHashItem + PartialEq, S: Clone + BuildHasher, A: Allocator> PartialEq for TriHashMap<T, S, A>

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T: TriHashItem + Eq, S: Clone + BuildHasher, A: Allocator> Eq for TriHashMap<T, S, A>

Auto Trait Implementations§

§

impl<T, S, A> Freeze for TriHashMap<T, S, A>
where S: Freeze, A: Freeze,

§

impl<T, S, A> RefUnwindSafe for TriHashMap<T, S, A>

§

impl<T, S, A> Send for TriHashMap<T, S, A>
where S: Send, T: Send, A: Send,

§

impl<T, S, A> Sync for TriHashMap<T, S, A>
where S: Sync, T: Sync, A: Sync,

§

impl<T, S, A> Unpin for TriHashMap<T, S, A>
where S: Unpin, A: Unpin, T: Unpin,

§

impl<T, S, A> UnwindSafe for TriHashMap<T, S, A>
where S: UnwindSafe, A: UnwindSafe, T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.