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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
//! Bijective (bidirectional) dictionary types with 1:1 key-value correspondence.
//!
//! This module provides dictionary implementations that support efficient lookups in both
//! directions: forward (term → value) and reverse (value → term). This is useful for:
//!
//! - **Embedding vocabularies**: Map tokens to sequential indices and back
//! - **Tokenization pipelines**: Efficiently convert between strings and numeric IDs
//! - **Symbolic mappings**: Bidirectional lookup for symbol tables, enum mappings, etc.
//!
//! # Key Types
//!
//! - [`BijectiveDictionary`]: Trait extending `MappedDictionary` with reverse lookup capability
//! - [`BijectiveMap`]: Generic bijective map for arbitrary hashable value types
//!
//! For vocabulary use cases with sequential `u64` indices, use
//! [`PersistentVocabARTrie`](crate::persistent_vocab_artrie::PersistentVocabARTrie) which provides
//! correct persistent bidirectional lookups via parent pointers and LRU caching.
//!
//! # Design
//!
//! The bijection invariant is strictly enforced:
//!
//! ```text
//! ∀ (k, v) in dictionary:
//! get_value(k) == Some(v) ⟺ get_term(&v) == Some(k)
//! ```
//!
//! **Duplicate handling**: Inserting a duplicate term or value causes a panic to preserve
//! the bijection invariant. Use `try_insert` for non-panicking insertion.
//!
//! # Examples
//!
//! ## BijectiveMap (Generic Values)
//!
//! ```rust
//! use libdictenstein::bijective::BijectiveMap;
//!
//! let bimap: BijectiveMap<String> = BijectiveMap::new();
//! bimap.insert("key1", "value1".to_string());
//! bimap.insert("key2", "value2".to_string());
//!
//! // Forward lookup
//! assert_eq!(bimap.get_value("key1"), Some("value1".to_string()));
//!
//! // Reverse lookup
//! assert_eq!(bimap.get_term(&"value1".to_string()).as_deref(), Some("key1"));
//! ```
//!
//! # Thread Safety
//!
//! `BijectiveMap` is thread-safe:
//! - Multiple concurrent reads are allowed
//! - Writes use locks for synchronization
//! - The bijection invariant is maintained across concurrent operations
pub use ;
use Cow;
use crateDictionaryValue;
use crateMappedDictionary;
/// A dictionary with 1:1 key-value correspondence supporting bidirectional lookup.
///
/// This trait extends [`MappedDictionary`] to provide reverse lookup capability,
/// enabling efficient value-to-term queries in addition to term-to-value queries.
///
/// # Bijection Invariant
///
/// For all `(k, v)` pairs in the dictionary:
///
/// ```text
/// get_value(k) == Some(v) ⟺ get_term(&v) == Some(k)
/// ```
///
/// This means:
/// - Every term maps to exactly one value
/// - Every value maps to exactly one term
/// - No two terms can share the same value
/// - No value exists without a corresponding term
///
/// # Performance
///
/// - Forward lookup (`get_value`): Inherited from [`MappedDictionary`], typically O(k)
/// - Reverse lookup (`get_term`): Implementation-dependent, often O(1) or O(log n)
///
/// # Examples
///
/// ```rust
/// use libdictenstein::bijective::{BijectiveDictionary, BijectiveMap};
///
/// let bimap = BijectiveMap::from_pairs([("hello", 0u64), ("world", 1u64)]);
///
/// // Forward lookup via MappedDictionary trait
/// use libdictenstein::MappedDictionary;
/// assert_eq!(bimap.get_value("hello"), Some(0u64));
///
/// // Reverse lookup via BijectiveDictionary trait (returns Cow<str>)
/// let term = BijectiveDictionary::get_term(&bimap, &0u64);
/// assert_eq!(term.as_deref(), Some("hello"));
/// ```