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