1use std::collections::HashMap;
23
24#[derive(Debug, Clone)]
27pub struct Bindful<S> {
28 bindings: HashMap<i32, S>,
29}
30
31impl<S: Clone> Bindful<S> {
32 pub fn new() -> Self {
35 Bindful {
36 bindings: HashMap::new(),
37 }
38 }
39
40 pub fn next_free(&self) -> i32 {
43 (1..)
44 .find(|n| !self.bindings.contains_key(n))
45 .unwrap_or(1)
46 }
47
48 pub fn bind(&mut self, n: i32, value: S) {
51 self.bindings.insert(n, value);
52 }
53
54 pub fn unbind(&mut self, n: i32) {
57 self.bindings.remove(&n);
58 }
59
60 pub fn binding(&self, n: i32) -> Option<S> {
63 self.bindings.get(&n).cloned()
64 }
65
66 pub fn get_values(&self) -> Vec<S> {
69 self.bindings.values().cloned().collect()
70 }
71
72 pub fn twiddle_bound<F>(&mut self, f: F)
75 where
76 F: Fn(&S) -> S,
77 {
78 let keys: Vec<i32> = self.bindings.keys().cloned().collect();
79 for n in keys {
80 if let Some(value) = self.bindings.get(&n).cloned() {
81 self.bindings.insert(n, f(&value));
82 }
83 }
84 }
85
86 pub fn with_binding<R, F>(&mut self, value: S, f: F) -> R
89 where
90 F: FnOnce(i32, &mut Self) -> R,
91 {
92 let n = self.next_free();
93 self.bind(n, value);
94 let result = f(n, self);
95 self.unbind(n);
96 result
97 }
98
99 pub fn bind_next(&mut self, value: S) -> i32 {
102 let n = self.next_free();
103 self.bind(n, value);
104 n
105 }
106}
107
108impl<S: Clone> Default for Bindful<S> {
109 fn default() -> Self {
110 Self::new()
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[test]
119 fn test_next_free() {
120 let bf: Bindful<String> = Bindful::new();
121 assert_eq!(bf.next_free(), 1);
122 }
123
124 #[test]
125 fn test_bind_and_binding() {
126 let mut bf = Bindful::new();
127 bf.bind(1, "hello".to_string());
128 assert_eq!(bf.binding(1), Some("hello".to_string()));
129 assert_eq!(bf.binding(2), None);
130 }
131
132 #[test]
133 fn test_unbind() {
134 let mut bf = Bindful::new();
135 bf.bind(1, "hello".to_string());
136 bf.unbind(1);
137 assert_eq!(bf.binding(1), None);
138 }
139
140 #[test]
141 fn test_with_binding() {
142 let mut bf = Bindful::new();
143 let result = bf.with_binding("temp".to_string(), |n, bf| {
144 assert_eq!(bf.binding(n), Some("temp".to_string()));
145 42
146 });
147 assert_eq!(result, 42);
148 assert_eq!(bf.binding(1), None); }
150
151 #[test]
152 fn test_twiddle_bound() {
153 let mut bf = Bindful::new();
154 bf.bind(1, 10);
155 bf.bind(2, 20);
156 bf.twiddle_bound(|x| x + 5);
157 assert_eq!(bf.binding(1), Some(15));
158 assert_eq!(bf.binding(2), Some(25));
159 }
160
161 #[test]
162 fn test_get_values() {
163 let mut bf = Bindful::new();
164 bf.bind(1, "a".to_string());
165 bf.bind(2, "b".to_string());
166 let mut values = bf.get_values();
167 values.sort();
168 assert_eq!(values, vec!["a".to_string(), "b".to_string()]);
169 }
170}