1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// SPDX-License-Identifier: AGPL-3.0-or-later
//! This module contains the [Bijection] type.

use super::HashMapWithDefault;
use log::error;
use std::{borrow::Borrow, hash::Hash};

/// Implements a bijection (one-to-one function) between a set of keys and a set of values.
/// Mapping from key to value and from value to key are both O(1) operations.
pub struct Bijection<K, V> {
    k2v: HashMapWithDefault<K, V>,
    v2k: HashMapWithDefault<V, K>,
}

impl<K, V> Bijection<K, V> {
    /// Creates a new [Bijection] with the given default key and value.
    pub fn new(default_key: K, default_value: V) -> Self {
        let k2v = HashMapWithDefault::new(default_value);
        let v2k = HashMapWithDefault::new(default_key);
        Self { k2v, v2k }
    }

    /// Returns a reference to the hash table which maps keys to values.
    pub fn k2v(&self) -> &HashMapWithDefault<K, V> {
        &self.k2v
    }

    /// Returns a reference to the hash table which maps values to keys.
    pub fn v2k(&self) -> &HashMapWithDefault<V, K> {
        &self.v2k
    }
}

impl<K: Clone + Hash + Eq, V: Clone + Hash + Eq> Bijection<K, V> {
    /// Inserts the given `(key, value)` pair. If this replaces an existing pair, then the old
    /// pair is returned.
    pub fn insert(&mut self, key: K, value: V) -> Option<(K, V)> {
        let key_clone = key.clone();
        let value_clone = value.clone();
        let old_value = self.k2v.get_mut().insert(key, value);
        let old_key = self.v2k.get_mut().insert(value_clone, key_clone);
        match (old_key, old_value) {
            (Some(old_key), Some(old_value)) => Some((old_key, old_value)),
            (None, None) => None,
            _ => {
                error!("logic error: unmatched key-value pair encountered in bijection insert");
                None
            }
        }
    }
}

impl<K: Hash + Eq, V> Bijection<K, V> {
    /// Returns the value associated with the given key. If no value is associated, then the default
    /// value is returned.
    pub fn value<Q: ?Sized + Hash + Eq>(&self, key: &Q) -> &V
    where
        K: Borrow<Q>,
    {
        self.k2v.get(key)
    }
}

impl<K, V: Hash + Eq> Bijection<K, V> {
    /// Returns the key associated with the given value. If no key is associated, then the default
    /// key is returned.
    pub fn key<R: ?Sized + Hash + Eq>(&self, value: &R) -> &K
    where
        V: Borrow<R>,
    {
        self.v2k.get(value)
    }
}