pub struct DHashMap<K1, K2, V, S = RandomState> { /* private fields */ }
Expand description

A hash map with double keys implemented as wrapper above two HashMaps.

Internally, two HashMap are created. One of type HashMap<K1, (K2, V)> to hold the (K2, V) tuple, and second one of type HashMap<K2, K1> just for holding the primary key of type K1. We hold the (K2, V) tuple inside first Hashmap for synchronization purpose, so that we can organize checking that both primary key of type K1 and the secondary key is of type K2 refer to the same value, and so on. Keys may be the same or different type.

By default, DHashMap as HashMap uses a hashing algorithm selected to provide resistance against HashDoS attacks. The algorithm is randomly seeded, and a reasonable best-effort is made to generate this seed from a high quality, secure source of randomness provided by the host without blocking the program. Because of this, the randomness of the seed depends on the output quality of the system’s random number generator when the seed is created. In particular, seeds generated when the system’s entropy pool is abnormally low such as during system boot may be of a lower quality.

The default hashing algorithm, like in HashMap, is currently SipHash 1-3, though this is subject to change at any point in the future. While its performance is very competitive for medium sized keys, other hashing algorithms will outperform it for small keys like integers as well as large keys like long strings, though those algorithms will typically not protect against attacks such as HashDoS.

The hashing algorithm can be replaced on a per-DHashMap basis using the default, with_hasher, and with_capacity_and_hasher methods. There are many alternative hashing algorithms available on crates.io.

It is required that the keys implement the Eq and Hash traits, although this can frequently be achieved by using #[derive(PartialEq, Eq, Hash)]. If you implement these yourself, it is important that the following property holds:

k1 == k2 -> hash(k1) == hash(k2)

In other words, if two keys are equal, their hashes must be equal.

It is a logic error for a key to be modified in such a way that the key’s hash, as determined by the Hash trait, or its equality, as determined by the Eq trait, changes while it is in the map. This is normally only possible through Cell, RefCell, global state, I/O, or unsafe code. The behavior resulting from such a logic error is not specified, but will not result in undefined behavior. This could include panics, incorrect results, aborts, memory leaks, and non-termination.

Implementations

Creates a new empty DHashMaps with RandomState type of hash builder to hash keys.

The primary key is of type K1 and the secondary key is of type K2. The value is of type V.

Internally, two HashMap are created. One of type HashMap<K1, (K2, V)> to hold the (K2, V) tuple, and second one of type HashMap<K2, K1> just for holding the primary key of type K1. We hold the (K2, V) tuple inside first Hashmap for synchronization purpose, so that we can organize checking both primary key of type K1 and the secondary key is of type K2 refer to the same value, and so on.

The hash map is initially created with a capacity of 0, so it will not allocate until it is first inserted into.

Examples
use double_map::DHashMap;
let mut map: DHashMap<u32, &str, i32> = DHashMap::new();

// The created DHashMap holds none elements
assert_eq!(map.len(), 0);

// The created DHashMap also doesn't allocate memory
assert_eq!(map.capacity(), 0);

// Now we insert element inside created DHashMap
map.insert(1, "One", 1);
// We can see that the DHashMap holds 1 element
assert_eq!(map.len(), 1);
// And it also allocates some capacity (by default it starts from 3 elements)
assert!(map.capacity() > 1);

Creates an empty DHashMap with the specified capacity.

The hash map will be able to hold at least capacity elements without reallocating. If capacity is 0, the hash map will not allocate.

Examples
use double_map::DHashMap;
let mut map: DHashMap<&str, i32, &str> = DHashMap::with_capacity(5);

// The created DHashMap holds none elements
assert_eq!(map.len(), 0);
// But it can hold at least 5 elements without reallocating
let empty_map_capacity = map.capacity();
assert!(empty_map_capacity >= 5);

// Now we insert some 5 elements inside created DHashMap
map.insert("One",   1, "a");
map.insert("Two",   2, "b");
map.insert("Three", 3, "c");
map.insert("Four",  4, "d");
map.insert("Five",  5, "e");

// We can see that the DHashMap holds 5 elements
assert_eq!(map.len(), 5);
// But its capacity isn't changed
assert_eq!(map.capacity(), empty_map_capacity)

Creates an empty DHashMap which will use the given hash builder to hash keys.

The created map has the default initial capacity, witch is equal to 0, so it will not allocate until it is first inserted into.

Warning: hash_builder is normally randomly generated, and is designed to allow DHashMap to be resistant to attacks that cause many collisions and very poor performance. Setting it manually using this function can expose a DoS attack vector.

The hash_builder passed should implement the BuildHasher trait for the DHashMap to be useful, see its documentation for details. It also should implement the Clone trait because we create two HashMaps inside the DHashMap, so that we need to clone hash_builder for passing it inside two inner HashMaps.

Examples
use double_map::DHashMap;
use std::collections::hash_map::RandomState;

let s = RandomState::new();
let mut map = DHashMap::with_hasher(s);

// The created DHashMap holds none elements
assert_eq!(map.len(), 0);

// The created DHashMap also doesn't allocate memory
assert_eq!(map.capacity(), 0);

// Now we insert elements inside created DHashMap
map.insert("One", 1, 2);
// We can see that the DHashMap holds 1 element
assert_eq!(map.len(), 1);
// And it also allocates some capacity (by default it starts from 3 elements)
assert!(map.capacity() > 1);

Creates an empty DHashMap with the specified capacity, using hash_builder to hash the keys.

The hash map will be able to hold at least capacity elements without reallocating. If capacity is 0, the hash map will not allocate.

Warning: hash_builder is normally randomly generated, and is designed to allow HashMaps to be resistant to attacks that cause many collisions and very poor performance. Setting it manually using this function can expose a DoS attack vector.

The hash_builder passed should implement the BuildHasher trait for the DHashMap to be useful, see its documentation for details. It also should implement the Clone trait because we create two HashMaps inside the DHashMap, so that we need to clone hash_builder for passing it inside two inner HashMaps.

Examples
use double_map::DHashMap;
use std::collections::hash_map::RandomState;

let s = RandomState::new();
let mut map = DHashMap::with_capacity_and_hasher(5, s);

// The created DHashMap holds none elements
assert_eq!(map.len(), 0);
// But it can hold at least 5 elements without reallocating
let empty_map_capacity = map.capacity();
assert!(empty_map_capacity >= 5);

// Now we insert some 5 elements inside the created DHashMap
map.insert("One",   1, "a");
map.insert("Two",   2, "b");
map.insert("Three", 3, "c");
map.insert("Four",  4, "d");
map.insert("Five",  5, "e");

// We can see that the DHashMap holds 5 elements
assert_eq!(map.len(), 5);
// But its capacity isn't changed
assert_eq!(map.capacity(), empty_map_capacity)

Returns the number of elements the map can hold without reallocating.

This number is a lower bound; the DHashMap<K1, K2, V> collection might be able to hold more, but is guaranteed to be able to hold at least this many.

Examples
use double_map::DHashMap;
let map = DHashMap::<i32, &str, &str>::with_capacity(16);

// The created DHashMap can hold at least 16 elements
assert!(map.capacity() >= 16);
// But for now it doesn't hold any elements
assert_eq!(map.len(), 0);

An iterator visiting all keys in arbitrary order. The iterator element is tuple of type (&'a K1, &'a K2).

Note

Internally DHashMap use two HashMap. One of type HashMap<K1, (K2, V)> to hold the (K2, V) tuple, and second one of type HashMap<K2, K1> just for holding the primary key of type K1.

Created iterator iterate only through first HashMap of type HashMap<K1, (K2, V)>. So that, if you previously used insert_unchecked method, this method can return false second keys (key #2) in case of unsynchronization between first keys of type K1 and second keys of type K2. See insert_unchecked method documentation for more.

Examples
use double_map::DHashMap;

let mut map = DHashMap::new();
map.insert("a", 1, "One");
map.insert("b", 2, "Two");
map.insert("c", 3, "Three");

assert_eq!(map.len(), 3);

for (key1, key2) in map.keys() {
    println!("key1: {}, key2: {}", key1, key2);
    assert!(
        (key1, key2) == (&"a", &1) ||
        (key1, key2) == (&"b", &2) ||
        (key1, key2) == (&"c", &3)
    );
}

assert_eq!(map.len(), 3);

An iterator visiting all values in arbitrary order. The iterator element type is &'a V.

Examples
use double_map::DHashMap;

let mut map = DHashMap::new();
map.insert("a", 1, "One");
map.insert("b", 2, "Two");
map.insert("c", 3, "Three");

assert_eq!(map.len(), 3);

for value in map.values() {
    println!("value = {}", value);
    assert!(value == &"One" || value == &"Two" || value == &"Three");
}

assert_eq!(map.len(), 3);

An iterator visiting all values mutably in arbitrary order. The iterator element type is &'a mut V.

Examples
use double_map::DHashMap;

let mut map = DHashMap::new();

map.insert("a", "One",   1);
map.insert("b", "Two",   2);
map.insert("c", "Three", 3);

assert_eq!(map.len(), 3);

for value in map.values_mut() {
    *value = *value + 10;
}

for value in map.values() {
    println!("value = {}", value);
    assert!(value == &11 || value == &12 || value == &13);
}

assert_eq!(map.len(), 3);

An iterator visiting all keys-value tuples in arbitrary order. The iterator element is tuple of type (&'a K1, &'a K2, &'a V).

Note

Internally DHashMap use two HashMap. One of type HashMap<K1, (K2, V)> to hold the (K2, V) tuple, and second one of type HashMap<K2, K1> just for holding the primary key of type K1.

Created iterator iterate only through first HashMap of type HashMap<K1, (K2, V)>. So that, if you previously used insert_unchecked method, this method can return false second keys (key #2) in case of unsynchronization between first keys of type K1 and second keys of type K2. See insert_unchecked method documentation for more.

Examples
use double_map::DHashMap;

let mut map = DHashMap::new();
map.insert("a", 1, "One");
map.insert("b", 2, "Two");
map.insert("c", 3, "Three");

assert_eq!(map.len(), 3);

for (key1, key2, value) in map.iter() {
    println!("key1: {}, key2: {}, value: {}", key1, key2, value);
    assert!(
        (key1, key2, value) == (&"a", &1, &"One") ||
        (key1, key2, value) == (&"b", &2, &"Two") ||
        (key1, key2, value) == (&"c", &3, &"Three")
    );
}

assert_eq!(map.len(), 3);

An iterator visiting all keys-value tuples in arbitrary order, with mutable references to the values. The iterator element is tuple of type(&'a K1, &'a K2, &'a mut V).

Note

Internally DHashMap use two HashMap. One of type HashMap<K1, (K2, V)> to hold the (K2, V) tuple, and second one of type HashMap<K2, K1> just for holding the primary key of type K1.

Created iterator iterate only through first HashMap of type HashMap<K1, (K2, V)>. So that, if you previously used insert_unchecked method, this method can return false second keys (key #2) in case of unsynchronization between first keys of type K1 and second keys of type K2. See insert_unchecked method documentation for more.

Examples
use double_map::DHashMap;

let mut map = DHashMap::new();
map.insert("a", "One",   1);
map.insert("b", "Two",   2);
map.insert("c", "Three", 3);

assert_eq!(map.len(), 3);

// Update all values
for (_, _, value) in map.iter_mut() {
    *value *= 2;
}

for (key1, key2, value) in map.iter() {
    println!("key1: {}, key2: {}, value: {}", key1, key2, value);
    assert!(
        (key1, key2, value) == (&"a", &"One",   &2) ||
        (key1, key2, value) == (&"b", &"Two",   &4) ||
        (key1, key2, value) == (&"c", &"Three", &6)
    );
}

assert_eq!(map.len(), 3);

Returns the number of elements in the map.

Examples
use double_map::{DHashMap, dhashmap};

let mut a = DHashMap::new();
// The created DHashMap doesn't hold any elements
assert_eq!(a.len(), 0);
// We insert one element
a.insert(1, "Breakfast", "Pancakes");
// And can be sure that DHashMap holds one element
assert_eq!(a.len(), 1);

let map = dhashmap![
   1, "Breakfast" => "Pancakes",
   2, "Lunch" => "Sandwich",
];
assert_eq!(map.len(), 2);

Returns true if the map contains no elements.

Examples
use double_map::DHashMap;

let mut a = DHashMap::new();
// The created DHashMap doesn't hold any elements, so it's empty
assert!(a.is_empty() && a.len() == 0);
// We insert one element
a.insert(1, "a", "One");
// And can be sure that DHashMap is not empty but holds one element
assert!(!a.is_empty() && a.len() == 1);

Clears the map, removing all keys-value tuples. Keeps the allocated memory for reuse.

Examples
use double_map::{DHashMap, dhashmap};

let mut a = dhashmap![
   1, "Breakfast" => "Pancakes",
   2, "Lunch" => "Sandwich",
];

// We can that see DHashMap holds two elements
assert_eq!(a.len(), 2);
let capacity_before_clearing = a.capacity();

a.clear();

// And now the map is empty and contains no elements
assert!(a.is_empty() && a.len() == 0);
// But map capacity is equal to the old one
assert_eq!(a.capacity(), capacity_before_clearing);

Returns a reference to the map’s BuildHasher.

Examples
use double_map::DHashMap;
use std::collections::hash_map::RandomState;

let hasher = RandomState::new();
let map: DHashMap<i32, i32, i32> = DHashMap::with_hasher(hasher);
let hasher: &RandomState = map.hasher();

Reserves capacity for at least additional more elements to be inserted in the DHashMap<K1, K2, V>. The collection may reserve more space to avoid frequent reallocations.

Panics

Panics if the new allocation size overflows usize::Max / 2.

Examples
use double_map::DHashMap;
let mut a = DHashMap::<&str, i128, &str>::new();
a.insert("apple",  1, "a");
a.insert("banana", 2, "b");
a.insert("cherry", 3, "c");

// We reserve space for additional 10 elements
a.reserve(10);
// And can see that created DHashMap can hold at least 13 elements
assert!(a.capacity() >= 13);

Tries to reserve capacity for at least additional more elements to be inserted in the given DHashMap<K1, K2, V>. The collection may reserve more space to avoid frequent reallocations.

Errors

If the capacity overflows, or the allocator reports a failure, then an error is returned.

Examples
use std::collections::TryReserveError;
use double_map::DHashMap;

let mut map: DHashMap<i32, &str, isize> = DHashMap::new();
map.try_reserve(20).expect("something go wrong");

// So everything is Ok
let capacity = map.capacity();
assert!(capacity >= 20);

// Let's check that it returns error if it can not reserve asked capacity
let result = map.try_reserve(usize::MAX);
match result {
    Err(_) => println!("It is ok, error was expected"),
    Ok(_) => unreachable!(),
}
// And capacity of the map isn't changed
assert_eq!(map.capacity(), capacity);

Shrinks the capacity of the map as much as possible. It will drop down as much as possible while maintaining the internal rules and possibly leaving some space in accordance with the resize policy.

Note that in general case the capacity is not guaranteed to shrink, but a zero-length DHashMap should generally shrink to capacity zero.

Examples
use double_map::DHashMap;
let mut a = DHashMap::<i32, &str, &str>::with_capacity(16);

// This DHashMap can hold at least 16 elements
let capacity_before_shrink = a.capacity();
assert!(capacity_before_shrink >= 16);

// And after shrinking, map capacity is less than before
a.shrink_to_fit();
assert!(a.capacity() < capacity_before_shrink);

// If we reserve some memory and insert some elements
a.reserve(10);
a.insert(1, "a", "One");
a.insert(2, "b", "Two");
assert!(a.capacity() >= 10);

// After applying shrink_to_fit method, the capacity less than
// reserved before, but inserted elements are still inside map
a.shrink_to_fit();
assert!(a.capacity() >= 2 && a.capacity() < 10);
assert_eq!(a.get_key1(&1), Some(&"One"));
assert_eq!(a.get_key1(&2), Some(&"Two"))

Shrinks the capacity of the map with a lower limit. It will drop down no lower than the supplied limit while maintaining the internal rules and possibly leaving some space in accordance with the resize policy.

If the current capacity is less than the lower limit, this is a no-op.

Examples
use double_map::DHashMap;

let mut map: DHashMap<i32, i32, i32> = DHashMap::with_capacity(100);
map.insert(1, 2, 3);
map.insert(4, 5, 6);
map.insert(7, 8, 9);
assert!(map.capacity() >= 100);

// We have only 3 elements inside map, so it works
map.shrink_to(10);
assert!(map.capacity() >= 10 && map.capacity() < 100);

// If we try shrink_to the capacity, that less than elements quantity inside map
map.shrink_to(0);
// So it works partially, but the resulting capacity is not less than quantity
// of elements inside the map
assert!(map.capacity() >= 3  && map.capacity() < 10);

Returns a reference to the value corresponding to the given primary key (key #1).

The key may be any borrowed form of the map’s key type, but Hash and Eq on the borrowed form must match those for the key type.

Examples
use double_map::DHashMap;

let mut map = DHashMap::new();
map.insert(1, "a", "One");
assert_eq!(map.get_key1(&1), Some(&"One"));
assert_eq!(map.get_key1(&2), None);

Returns a reference to the value corresponding to the given secondary key (key #2).

The key may be any borrowed form of the map’s key type, but Hash and Eq on the borrowed form must match those for the key type.

Examples
use double_map::DHashMap;

let mut map = DHashMap::new();
map.insert(1, "a", "One");
assert_eq!(map.get_key2(&"a"), Some(&"One"));
assert_eq!(map.get_key2(&"b"), None);

Returns true if the map contains a value for the specified primary key (key #1) of type K1.

The key may be any borrowed form of the map’s key type, but Hash and Eq on the borrowed form must match those for the key type

Example
use double_map::{DHashMap, dhashmap};

let map = dhashmap! {
    1, "One" => String::from("Eins"),
    2, "Two" => String::from("Zwei"),
    3, "Three" => String::from("Drei"),
};

assert!( map.contains_key1(&1));
assert!(!map.contains_key1(&4));

Returns true if the map contains a value for the specified secondary key (key #2) of type K2.

The key may be any borrowed form of the map’s key type, but Hash and Eq on the borrowed form must match those for the key type

Example
use double_map::{DHashMap, dhashmap};

let map = dhashmap! {
    1, "One" => String::from("Eins"),
    2, "Two" => String::from("Zwei"),
    3, "Three" => String::from("Drei"),
};

assert!( map.contains_key2(&"One") );
assert!(!map.contains_key2(&"Four"));

Returns true if the map contains a value for the specified primary key (key #1) of type K1 and secondary key (key #2) of type K2 if they both refer to the same value.

The keys may be any borrowed form of the map’s key type, but Hash and Eq on the borrowed form must match those for the keys type.

Note

Note that this contains_keys method return true only if two keys exist and refer to the same value.

Example
use double_map::{DHashMap, dhashmap};

let map = dhashmap! {
    1, "One" => String::from("Eins"),
    2, "Two" => String::from("Zwei"),
    3, "Three" => String::from("Drei"),
};

// two keys exist and refer to the same value ("Eins")
assert_eq!(map.contains_keys(&1, &"One" ), true );

// Both keys don't exist
assert_eq!(map.contains_keys(&4, &"Four"), false);

// Both keys exist but refer to the different value (key1: 1 refers to "Eins",
// key2: "Two" refers to "Zwei")
assert_eq!(map.contains_keys(&1, &"Two" ), false);
assert!(map.contains_key1(&1)     == true && map.get_key1(&1).unwrap()     == "Eins");
assert!(map.contains_key2(&"Two") == true && map.get_key2(&"Two").unwrap() == "Zwei");

Returns a mutable reference to the value corresponding to the given primary key (key #1).

The key may be any borrowed form of the map’s key type, but Hash and Eq on the borrowed form must match those for the key type.

Examples
use double_map::DHashMap;

let mut map = DHashMap::new();
map.insert(1, "a", "One");
if let Some(x) = map.get_mut_key1(&1) {
    *x = "First";
}
assert_eq!(map.get_key1(&1), Some(&"First"));

Returns a mutable reference to the value corresponding to the given secondary key (key #2).

The key may be any borrowed form of the map’s key type, but Hash and Eq on the borrowed form must match those for the key type.

Examples
use double_map::DHashMap;

let mut map = DHashMap::new();
map.insert(1, "a", "One");
if let Some(x) = map.get_mut_key2(&"a") {
    *x = "First";
}
assert_eq!(map.get_key2(&"a"), Some(&"First"));

Removes element from the map using a primary key (key #1), returning the value corresponding to the key if the key was previously in the map. Keeps the allocated memory for reuse.

The key may be any borrowed form of the map’s key type, but Hash and Eq on the borrowed form must match those for the key type.

Note

This method removes not only value, but whole element includng primary K1 and secondary K2 keys

Examples
use double_map::{DHashMap, dhashmap};

// We create map with three elements
let mut map = dhashmap! {
    1, "One"   => String::from("Eins"),
    2, "Two"   => String::from("Zwei"),
    3, "Three" => String::from("Drei"),
};

// We can see that DHashMap holds three elements
assert!(map.len() == 3 && map.capacity() >= 3);

// Also we reserve memory for holdind additionally at least 20 elements,
// so that DHashMap can hold 23 elements or more
map.reserve(20);
let capacity_before_remove = map.capacity();

// We remove element with key #1 from the map and get corresponding value
assert_eq!(map.remove_key1(&1), Some("Eins".to_owned()));
// If we try to remove the same element with key #1 twise we get None,
// because that element was already removed
assert_eq!(map.remove_key1(&1), None);

// Now we remove all elements one by one, and can see that map holds nothing
map.remove_key1(&2);
map.remove_key1(&3);
assert_eq!(map.len(), 0);

// But map capacity is equal to the old one and can hold at least 23 elements
assert!(map.capacity() == capacity_before_remove && map.capacity() >= 23);

Removes element from the map using a secondary key (key #2), returning the value corresponding to the key if the key was previously in the map. Keeps the allocated memory for reuse.

The key may be any borrowed form of the map’s key type, but Hash and Eq on the borrowed form must match those for the key type.

Note

This method removes not only value, but whole element includng primary K1 and secondary K2 keys

Examples
use double_map::{DHashMap, dhashmap};

// We create map with three elements
let mut map = dhashmap! {
    1, "One"   => String::from("Eins"),
    2, "Two"   => String::from("Zwei"),
    3, "Three" => String::from("Drei"),
};

// We can see that DHashMap holds three elements
assert!(map.len() == 3 && map.capacity() >= 3);

// Also we reserve memory for holdind additionally at least 20 elements,
// so that DHashMap can hold 23 elements or more
map.reserve(20);
let capacity_before_remove = map.capacity();

// We remove element with key #1 from the map and get corresponding value
assert_eq!(map.remove_key2(&"One"), Some("Eins".to_owned()));
// If we try to remove the same element with key #1 twise we get None,
// because that element was already removed
assert_eq!(map.remove_key2(&"One"), None);

// Now we remove all elements one by one, and can see that map holds nothing
map.remove_key2(&"Two");
map.remove_key2(&"Three");
assert_eq!(map.len(), 0);

// But map capacity is equal to the old one and can hold at least 23 elements
assert!(map.capacity() == capacity_before_remove && map.capacity() >= 23);

Tries to get the given keys’ corresponding entry in the map for in-place manipulation.

Returns Entry enum if all of the following is true:

  • Both key #1 and key #2 are vacant.
  • If both key #1 and key #2 exist, they refer to the same value.

When the above statements are false, entry method returns EntryError structure which contains the ErrorKind enum, and the values of provided keys that were not used for creation entry (that can be used for another purpose).

Depending on the points below, different ErrorKind variants may be returned:

Examples
use double_map::DHashMap;
use double_map::dhash_map::ErrorKind;

let mut letters = DHashMap::new();

for ch in "a short treatise on fungi".chars() {
    if let Ok(entry) = letters.entry(ch.clone(), ch) {
        let counter = entry.or_insert(0);
        *counter += 1;
    }
}

assert_eq!(letters.get_key1(&'s'), Some(&2));
assert_eq!(letters.get_key1(&'t'), Some(&3));
assert_eq!(letters.get_key1(&'u'), Some(&1));
assert_eq!(letters.get_key1(&'y'), None);

// Return `ErrorKind::OccupiedK1AndVacantK2` if key #1 already
// exists with some value, but key #2 is vacant.
let error_kind = letters.entry('s', 'y').unwrap_err().error;
assert_eq!(error_kind, ErrorKind::OccupiedK1AndVacantK2);

// Return `ErrorKind::VacantK1AndOccupiedK2` if key #1 is vacant,
// but key #2 already exists with some value.
let error_kind = letters.entry('y', 's').unwrap_err().error;
assert_eq!(error_kind, ErrorKind::VacantK1AndOccupiedK2);

// Return `ErrorKind::KeysPointsToDiffEntries` if both
// key #1 and key #2 already exist with some values,
// but point to different entries (values).
let error_kind = letters.entry('s', 't').unwrap_err().error;
assert_eq!(error_kind, ErrorKind::KeysPointsToDiffEntries);

Inserts given keys and value into the map without checking. Update the value if key #1 of type K1 already presents with returning old value.

If the map did not have these keys present, None is returned.

Warning

Using this method can lead to unsynchronization between key #1 and key #1, so that they can refer to different values. It also can lead to different quantity of keys, so that quantity of keys #2 K2 can be less than quantity of keys #1 K1.

If the map did have these keys vacant or present and both keys refer to the same value it is Ok, the value is updated, and the old value is returned inside Some(V) variant.

But for this method, it doesn’t matter if key # 2 exists or not, it returns updated value also if the map contains only key #1. It is because this method doesn’t check that:

  • key #1 is vacant, but key #2 already exists with some value;
  • key #1 already exists with some value, but key #2 is vacant;
  • both key #1 and key #2 already exist with some values, but point to different entries (values).

The keys are not updated, though; this matters for types that can be == without being identical. See the std module-level documentation for more.

Note

Using this method is cheaper than using another insertion entry, insert and try_insert methods.

Links between keys #1 K1 and the values that they refer are adequate. Unsynchronization between key #1 and key #2, lead only to that the key # 2 may refer to unexpected value.

It is recommended to use this method only if you are sure that key #1 and key #2 are unique. For example if key #1 of type K1 is generated automatically and you check only that there is no key #2 of type K2.

Examples
use double_map::DHashMap;
use core::hash::Hash;

let mut map = DHashMap::new();

// Returns None if keys are vacant
assert_eq!(map.insert_unchecked(1, "a", "One"), None);
assert_eq!(map.is_empty(), false);

// If the map did have these keys present, the value is updated,
// and the old value is returned inside `Some(V)` variants
map.insert_unchecked(2, "b", "Two");
assert_eq!(map.insert_unchecked(2, "b", "Second"), Some("Two"));
assert_eq!(map.get_key1(&2), Some(&"Second"));

// But method does not care about key #2
assert_eq!(map.insert_unchecked(1, "b", "First"), Some("One"));
// So key # 2 refers to unexpected value, and now we have double second keys
// referring to the same value
assert_eq!(map.get_key2(&"a"), Some(&"First"));
assert_eq!(map.get_key2(&"b"), Some(&"First"));

// But it can be safe if you generate one key automatically, and check
// existence only other key. It can be for example like that:
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct PupilID(usize);

pub struct Pupil {
    name: String
}

pub struct Class {
    pupils: DHashMap<PupilID, String, Pupil>,
    len: usize,
}

impl Class {
    pub fn new() -> Class {
        Self{
            pupils: DHashMap::new(),
            len: 0
        }
    }
    pub fn contains_name(&self, name: &String) -> bool {
        self.pupils.get_key2(name).is_some()
    }
    pub fn add_pupil(&mut self, name: String) -> Option<PupilID> {
        if !self.contains_name(&name) {
            let len = &mut self.len;
            let id = PupilID(*len);
            self.pupils.insert_unchecked( id, name.clone(), Pupil { name } );
            *len += 1;
            Some(id)
        } else {
            None
        }
    }
}

Tries to insert given keys and value into the map. Update the value if keys are already present and refer to the same value with returning old value.

If the map did not have these keys present, None is returned.

If the map did have these key present, and both keys refer to the same value, the value is updated, and the old value is returned inside Some(Ok(V)) variants. The key is not updated, though; this matters for types that can be == without being identical. See the std module-level documentation for more.

The insert method returns InsertError structure (inside of Some(Err(_)) variants):

  • when key #1 is vacant, but key #2 already exists with some value;
  • when key #1 already exists with some value, but key #2 is vacant;
  • when both key #1 and key #2 already exist with some values, but point to different entries (values).

The above mentioned error kinds can be matched through the ErrorKind enum. Returned InsertError structure also contains provided keys and value that were not inserted and can be used for another purpose.

Examples
use double_map::DHashMap;
use double_map::dhash_map::{InsertError, ErrorKind};
let mut map = DHashMap::new();

// Returns None if keys are vacant
assert_eq!(map.insert(1, "a", "One"), None);
assert_eq!(map.is_empty(), false);

// If the map did have these keys present, and both keys refer to
// the same value, the value is updated, and the old value is returned
// inside `Some(Ok(V))` variants
map.insert(2, "b", "Two");
assert_eq!(map.insert(2, "b", "Second"), Some(Ok("Two")));
assert_eq!(map.get_key1(&2), Some(&"Second"));

// Returns `ErrorKind::OccupiedK1AndVacantK2` if key #1 already
// exists with some value, but key #2 is vacant. Error structure
// also contains provided keys and value
match map.insert(1, "c", "value") {
    Some(Err(InsertError{ error, keys, value })) => {
        assert_eq!(error, ErrorKind::OccupiedK1AndVacantK2);
        assert_eq!(keys, (1, "c"));
        assert_eq!(value, "value");
    }
    _ => unreachable!(),
}

// Returns `ErrorKind::VacantK1AndOccupiedK2` if key #1 is vacant,
// but key #2 already exists with some value.
let error_kind = map.insert(3, "a", "value").unwrap().unwrap_err().error;
assert_eq!(error_kind, ErrorKind::VacantK1AndOccupiedK2);

// Returns `ErrorKind::KeysPointsToDiffEntries` if both
// key #1 and key #2 already exist with some values,
// but point to different entries (values).
let error_kind = map.insert(1, "b", "value").unwrap().unwrap_err().error;
assert_eq!(error_kind, ErrorKind::KeysPointsToDiffEntries);

Tries to insert given keys and value into the map, and returns a mutable reference to the value in the entry if the map did not have these keys present.

If the map did have these keys present, and both keys refer to the same value, nothing is updated, and a TryInsertError::Occupied enum variant error containing OccupiedError structure is returned. The OccupiedError contains the occupied entry OccupiedEntry, and the value that was not inserted.

The try_insert method return InsertError structure (inside of TryInsertError::Insert variant):

  • when key #1 is vacant, but key #2 already exists with some value;
  • when key #1 already exists with some value, but key #2 is vacant;
  • when both key #1 and key #2 already exist with some values, but point to different entries (values).

The above mentioned error kinds can be matched through the ErrorKind enum. Returned InsertError structure also contains provided keys and value that were not inserted and can be used for another purpose.

Examples
use double_map::DHashMap;
use double_map::dhash_map::{TryInsertError, OccupiedError, InsertError, ErrorKind};


let mut map = DHashMap::new();

// Returns mutable reference to the value if keys are vacant
let value = map.try_insert(1, "a", "One").unwrap();
assert_eq!(value, &"One");
*value = "First";
assert_eq!(map.get_key1(&1), Some(&"First"));

// If the map did have these keys present, and both keys refer to
// the same value, nothing is updated, and the provided value
// is returned inside `Err(TryInsertError::Occupied(_))` variants
map.try_insert(2, "b", "Two");
match map.try_insert(2, "b", "Second") {
    Err(error) => match error {
        TryInsertError::Occupied(OccupiedError{ entry, value }) => {
            assert_eq!(entry.keys(), (&2, &"b"));
            assert_eq!(entry.get(), &"Two");
            assert_eq!(value, "Second");
        }
        _ => unreachable!(),
    }
    _ => unreachable!(),
}
assert_eq!(map.get_key1(&2), Some(&"Two"));

// Returns `ErrorKind::OccupiedK1AndVacantK2` if key #1 already
// exists with some value, but key #2 is vacant. Error structure
// also contains provided keys and value
match map.try_insert(1, "c", "value") {
    Err(error) => match error {
        TryInsertError::Insert(InsertError{ error, keys, value }) => {
            assert_eq!(error, ErrorKind::OccupiedK1AndVacantK2);
            assert_eq!(keys, (1, "c"));
            assert_eq!(value, "value");
        }
        _ => unreachable!()
    }
    _ => unreachable!(),
}

// Returns `ErrorKind::VacantK1AndOccupiedK2` if key #1 is vacant,
// but key #2 already exists with some value.
match map.try_insert(3, "a", "value") {
    Err(error) => match error {
        TryInsertError::Insert(InsertError{ error, .. }) => {
            assert_eq!(error, ErrorKind::VacantK1AndOccupiedK2);
        }
        _ => unreachable!()
    }
    _ => unreachable!(),
}

// Returns `ErrorKind::KeysPointsToDiffEntries` if both
// key #1 and key #2 already exist with some values,
// but point to different entries (values).
match map.try_insert(1, "b", "value") {
    Err(error) => match error {
        TryInsertError::Insert(InsertError{ error, .. }) => {
            assert_eq!(error, ErrorKind::KeysPointsToDiffEntries);
        }
        _ => unreachable!()
    }
    _ => unreachable!(),
}

Trait Implementations

Returns a copy of the value. Read more

Performs copy-assignment from source. Read more

Creates an empty DHashMap<K1, K2, V, S>, with the Default value for the hasher.

Creates an empty DHashMap<K1, K2, V, S>, with the Default value for the hasher.

Examples
use double_map::DHashMap;
use std::collections::hash_map::RandomState;

// You need to specify all types of DHashMap, including hasher.
// Created map is empty and don't allocate memory
let map: DHashMap<u32, String, String, RandomState> = Default::default();
assert_eq!(map.capacity(), 0);
let map: DHashMap<u32, String, String, RandomState> = DHashMap::default();
assert_eq!(map.capacity(), 0);

Inserts all new keys and values from the iterator to existing DHashMap<K1, K2, V, S>.

Inserts all new keys and values from the iterator to existing DHashMap<K1, K2, V, S>.

Replace values with existing keys with new values returned from the iterator. The keys and values must implement Copy trait.

Examples
use double_map::DHashMap;

// Let's create `DHashMap` with std::collections::hash_map::RandomState hasher
let mut map = DHashMap::new();
map.insert(1, 1, 999);

let mut number = 0;
let some_vec: Vec<_> = std::iter::repeat_with(move || {
    number +=1;
    (number, number, number * 10)
}).take(5).collect();

// You don't need to specify the hasher
let some_iter = some_vec.iter().map(|(k1, k2, v)| (k1, k2, v));
map.extend(some_iter);

// Replace values with existing keys with new values returned from the iterator.
// So that the map.get_key1(&1) doesn't return Some(&999).
assert_eq!(map.get_key1(&1), Some(&10));
assert_eq!(map.get_key1(&5), Some(&50));
assert_eq!(map.get_key1(&6), None);

// And created vector are still can be used.
assert_eq!(some_vec[4], (5, 5, 50));
🔬 This is a nightly-only experimental API. (extend_one)

Extends a collection with exactly one element.

🔬 This is a nightly-only experimental API. (extend_one)

Reserves capacity in a collection for the given number of additional elements. Read more

Inserts all new keys and values from the iterator to existing DHashMap<K1, K2, V, S>.

Inserts all new keys and values from the iterator to existing DHashMap<K1, K2, V, S>.

Replace values with existing keys with new values returned from the iterator.

Examples
use double_map::DHashMap;

// Let's create `DHashMap` with std::collections::hash_map::RandomState hasher
let mut map = DHashMap::new();
map.insert(1, 1, 999);

let mut number = 0;
let some_iter = std::iter::repeat_with(move || {
    number +=1;
    (number, number, number * 10)
}).take(5);

// You don't need to specify the hasher
map.extend(some_iter);
// Replace values with existing keys with new values returned from the iterator.
// So that the map.get_key1(&1) doesn't return Some(&999).
assert_eq!(map.get_key1(&1), Some(&10));

let some_vec: Vec<_> = std::iter::repeat_with(move || {
    number +=100;
    (number, number, number * 10)
}).take(5).collect();
map.extend(some_vec);

let some_arr = [(11, 11, 111), (22, 22, 222), (33, 33, 333), (44, 44, 4444), (55, 55, 555)];
map.extend(some_arr);

// Keys and values from some_iter
assert_eq!(map.get_key1(&1), Some(&10));
assert_eq!(map.get_key1(&5), Some(&50));
assert_eq!(map.get_key1(&6), None);

// Keys and values from some_vec
assert_eq!(map.get_key1(&100), Some(&1000));
assert_eq!(map.get_key1(&500), Some(&5000));
assert_eq!(map.get_key1(&600), None);

// Keys and values from some_arr
assert_eq!(map.get_key1(&11), Some(&111));
assert_eq!(map.get_key1(&55), Some(&555));
assert_eq!(map.get_key1(&66), None);
🔬 This is a nightly-only experimental API. (extend_one)

Extends a collection with exactly one element.

🔬 This is a nightly-only experimental API. (extend_one)

Reserves capacity in a collection for the given number of additional elements. Read more

Creates an new DHashMap<K1, K2, V, S>, with the Default value for the hasher from from an iterator.

Creates an new DHashMap<K1, K2, V, S>, with the Default value for the hasher from from an iterator.

You need to specify the type of hasher

Examples
use double_map::DHashMap;
use std::collections::hash_map::RandomState;

let mut number = 0;
let some_iter = std::iter::repeat_with(move || {
    number +=1;
    (number, number, number * 10)
}).take(5);
// You need to specify hasher
let map: DHashMap<_, _, _, RandomState> = DHashMap::from_iter(some_iter.clone());
assert_eq!(map.get_key1(&1), Some(&10));
assert_eq!(map.get_key1(&5), Some(&50));
assert_eq!(map.get_key1(&6), None);

let some_vec: Vec<_> = some_iter.collect();
let map: DHashMap<_, _, _, RandomState> = DHashMap::from_iter(some_vec);
assert_eq!(map.get_key1(&1), Some(&10));
assert_eq!(map.get_key1(&5), Some(&50));
assert_eq!(map.get_key1(&6), None);

let some_arr = [(1, 1, 10), (2, 2, 20), (3, 3, 30), (4, 4, 40), (5, 5, 50)];
let map: DHashMap<_, _, _, RandomState> = DHashMap::from_iter(some_arr);
assert_eq!(map.get_key1(&1), Some(&10));
assert_eq!(map.get_key1(&5), Some(&50));
assert_eq!(map.get_key1(&6), None);

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

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

The resulting type after obtaining ownership.

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

🔬 This is a nightly-only experimental API. (toowned_clone_into)

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

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.