logicaffeine_data/
indexing.rs1use std::collections::HashMap;
20use std::hash::Hash;
21
22pub trait LogosIndex<I> {
41 type Output;
43 fn logos_get(&self, index: I) -> Self::Output;
45}
46
47pub trait LogosIndexMut<I>: LogosIndex<I> {
65 fn logos_set(&mut self, index: I, value: Self::Output);
67}
68
69impl<T: Clone> LogosIndex<i64> for Vec<T> {
72 type Output = T;
73
74 fn logos_get(&self, index: i64) -> T {
75 if index < 1 {
76 panic!("Index {} is invalid: LOGOS uses 1-based indexing (minimum is 1)", index);
77 }
78 let idx = (index - 1) as usize;
79 if idx >= self.len() {
80 panic!("Index {} is out of bounds for seq of length {}", index, self.len());
81 }
82 self[idx].clone()
83 }
84}
85
86impl<T: Clone> LogosIndexMut<i64> for Vec<T> {
87 fn logos_set(&mut self, index: i64, value: T) {
88 if index < 1 {
89 panic!("Index {} is invalid: LOGOS uses 1-based indexing (minimum is 1)", index);
90 }
91 let idx = (index - 1) as usize;
92 if idx >= self.len() {
93 panic!("Index {} is out of bounds for seq of length {}", index, self.len());
94 }
95 self[idx] = value;
96 }
97}
98
99impl<K: Eq + Hash, V: Clone> LogosIndex<K> for HashMap<K, V> {
102 type Output = V;
103
104 fn logos_get(&self, key: K) -> V {
105 self.get(&key).cloned().expect("Key not found in map")
106 }
107}
108
109impl<K: Eq + Hash, V: Clone> LogosIndexMut<K> for HashMap<K, V> {
110 fn logos_set(&mut self, key: K, value: V) {
111 self.insert(key, value);
112 }
113}
114
115impl<V: Clone> LogosIndex<&str> for HashMap<String, V> {
118 type Output = V;
119
120 fn logos_get(&self, key: &str) -> V {
121 self.get(key).cloned().expect("Key not found in map")
122 }
123}
124
125impl<V: Clone> LogosIndexMut<&str> for HashMap<String, V> {
126 fn logos_set(&mut self, key: &str, value: V) {
127 self.insert(key.to_string(), value);
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn vec_1_based_indexing() {
137 let v = vec![10, 20, 30];
138 assert_eq!(LogosIndex::logos_get(&v, 1i64), 10);
139 assert_eq!(LogosIndex::logos_get(&v, 2i64), 20);
140 assert_eq!(LogosIndex::logos_get(&v, 3i64), 30);
141 }
142
143 #[test]
144 #[should_panic(expected = "1-based indexing")]
145 fn vec_zero_index_panics() {
146 let v = vec![10, 20, 30];
147 let _ = LogosIndex::logos_get(&v, 0i64);
148 }
149
150 #[test]
151 fn vec_set_1_based() {
152 let mut v = vec![10, 20, 30];
153 LogosIndexMut::logos_set(&mut v, 2i64, 99);
154 assert_eq!(v, vec![10, 99, 30]);
155 }
156
157 #[test]
158 fn hashmap_string_key() {
159 let mut m: HashMap<String, i64> = HashMap::new();
160 m.insert("iron".to_string(), 42);
161 assert_eq!(LogosIndex::logos_get(&m, "iron".to_string()), 42);
162 }
163
164 #[test]
165 fn hashmap_str_key() {
166 let mut m: HashMap<String, i64> = HashMap::new();
167 m.insert("iron".to_string(), 42);
168 assert_eq!(LogosIndex::logos_get(&m, "iron"), 42);
169 }
170
171 #[test]
172 fn hashmap_set_key() {
173 let mut m: HashMap<String, i64> = HashMap::new();
174 LogosIndexMut::logos_set(&mut m, "iron", 42i64);
175 assert_eq!(m.get("iron"), Some(&42));
176 }
177}