Skip to main content

panopticon_core/data/
handle.rs

1use crate::imports::*;
2
3/// A draft-time builder for populating an array entry in the [`Store`].
4///
5/// Returned by [`Pipeline::array`] and [`Store::define_array`]. Methods
6/// are chainable so nested structures can be built in a single
7/// expression. Nested arrays and maps are added via
8/// [`push_array`](ArrayHandle::push_array) and
9/// [`push_map`](MapHandle::insert_map) and return child handles borrowing
10/// from this one.
11pub struct ArrayHandle<'a, T = StoreEntry> {
12    name: String,
13    data: &'a mut Vec<T>,
14}
15
16/// A draft-time builder for populating a map entry in the [`Store`].
17///
18/// Returned by [`Pipeline::map`] and [`Store::define_map`]. Methods are
19/// chainable so nested structures can be built in a single expression.
20/// Nested arrays and maps are added via [`insert_array`](MapHandle::insert_array)
21/// and [`insert_map`](MapHandle::insert_map) and return child handles
22/// borrowing from this one.
23pub struct MapHandle<'a, T = StoreEntry> {
24    name: String,
25    data: &'a mut HashMap<String, T>,
26}
27
28impl<'a, T> ArrayHandle<'a, T> {
29    /// Wraps a mutable vector in a handle under the given display name.
30    /// Intended for extension code; user code obtains handles through
31    /// [`Pipeline::array`] or [`Store::define_array`].
32    pub fn new<N: Into<String>>(name: N, data: &'a mut Vec<T>) -> Self {
33        Self {
34            name: name.into(),
35            data,
36        }
37    }
38
39    /// Appends a value to the array. Returns a mutable reference for
40    /// chaining.
41    pub fn push<V: Into<T>>(&mut self, value: V) -> Result<&mut Self, StoreError> {
42        self.data.push(value.into());
43        Ok(self)
44    }
45}
46
47impl<'a, T> MapHandle<'a, T> {
48    /// Wraps a mutable map in a handle under the given display name.
49    /// Intended for extension code; user code obtains handles through
50    /// [`Pipeline::map`] or [`Store::define_map`].
51    pub fn new<N: Into<String>>(name: N, data: &'a mut HashMap<String, T>) -> Self {
52        Self {
53            name: name.into(),
54            data,
55        }
56    }
57
58    /// Inserts a key/value pair into the map. Returns a mutable reference
59    /// for chaining. An existing entry under the same key is overwritten.
60    pub fn insert<V: Into<T>, K: Into<String>>(
61        &mut self,
62        key: K,
63        value: V,
64    ) -> Result<&mut Self, StoreError> {
65        self.data.insert(key.into(), value.into());
66        Ok(self)
67    }
68}
69
70mod store_entry {
71    use crate::imports::*;
72    // Explicit support for StoreEntry — the default element type these
73    // handles work with — where nested arrays and maps are themselves
74    // StoreEntry values.
75    impl<'a> ArrayHandle<'a, StoreEntry> {
76        /// Appends a new nested array entry and returns a child handle
77        /// borrowing from this one to populate it.
78        pub fn push_array(&mut self) -> Result<ArrayHandle<'_, StoreEntry>, StoreError> {
79            self.data.push(StoreEntry::Array(Vec::new()));
80            let idx = self.data.len() - 1;
81            let inner = match &mut self.data[idx] {
82                StoreEntry::Array(arr) => arr,
83                _ => unreachable!(),
84            };
85            let name = format!("{}[{}]", self.name, idx);
86            Ok(ArrayHandle::new(name, inner))
87        }
88
89        /// Appends a new nested map entry and returns a child handle
90        /// borrowing from this one to populate it.
91        pub fn push_map(&mut self) -> Result<MapHandle<'_, StoreEntry>, StoreError> {
92            self.data.push(StoreEntry::Map(HashMap::new()));
93            let idx = self.data.len() - 1;
94            let inner = match &mut self.data[idx] {
95                StoreEntry::Map(map) => map,
96                _ => unreachable!(),
97            };
98            let name = format!("{}[{}]", self.name, idx);
99            Ok(MapHandle::new(name, inner))
100        }
101    }
102
103    impl<'a> MapHandle<'a, StoreEntry> {
104        /// Inserts a new nested array entry under `key` and returns a
105        /// child handle borrowing from this one to populate it.
106        pub fn insert_array<K: Into<String>>(
107            &mut self,
108            key: K,
109        ) -> Result<ArrayHandle<'_, StoreEntry>, StoreError> {
110            let key = key.into();
111            self.data.insert(key.clone(), StoreEntry::Array(Vec::new()));
112            let inner = match self.data.get_mut(&key) {
113                Some(StoreEntry::Array(arr)) => arr,
114                _ => unreachable!(),
115            };
116            let name = format!("{}.{}", self.name, key);
117            Ok(ArrayHandle::new(name, inner))
118        }
119
120        /// Inserts a new nested map entry under `key` and returns a child
121        /// handle borrowing from this one to populate it.
122        pub fn insert_map<K: Into<String>>(
123            &mut self,
124            key: K,
125        ) -> Result<MapHandle<'_, StoreEntry>, StoreError> {
126            let key = key.into();
127            self.data
128                .insert(key.clone(), StoreEntry::Map(HashMap::new()));
129            let inner = match self.data.get_mut(&key) {
130                Some(StoreEntry::Map(map)) => map,
131                _ => unreachable!(),
132            };
133            let name = format!("{}.{}", self.name, key);
134            Ok(MapHandle::new(name, inner))
135        }
136
137        /// Inserts a nested array under `key` and hands it to a closure
138        /// for population. Useful when the nested structure would
139        /// otherwise force awkward temporaries.
140        pub fn with_array<
141            K: Into<String>,
142            F: FnOnce(&mut ArrayHandle<'_, StoreEntry>) -> Result<(), StoreError>,
143        >(
144            &mut self,
145            key: K,
146            body: F,
147        ) -> Result<(), StoreError> {
148            let key = key.into();
149            let mut arr_handle = self.insert_array(key)?;
150            body(&mut arr_handle)
151        }
152        /// Inserts a nested map under `key` and hands it to a closure for
153        /// population.
154        pub fn with_map<
155            K: Into<String>,
156            F: FnOnce(&mut MapHandle<'_, StoreEntry>) -> Result<(), StoreError>,
157        >(
158            &mut self,
159            key: K,
160            body: F,
161        ) -> Result<(), StoreError> {
162            let key = key.into();
163            let mut map_handle = self.insert_map(key)?;
164            body(&mut map_handle)
165        }
166    }
167}
168
169mod homogeneous {
170    use crate::imports::*;
171    // Extension-facing helpers for homogeneous collections (`Vec<T>`,
172    // `HashMap<String, T>`) where the element type isn't `StoreEntry`.
173    // Core pipeline code works in terms of `StoreEntry`, but extension
174    // crates sometimes want the same handle patterns for simpler data.
175    impl<'a, T> ArrayHandle<'a, Vec<T>> {
176        /// Appends a new inner `Vec<T>` and returns a child array handle
177        /// for populating it.
178        pub fn push_array(&mut self) -> Result<ArrayHandle<'_, T>, StoreError> {
179            self.data.push(Vec::new());
180            let idx = self.data.len() - 1;
181            let inner = &mut self.data[idx];
182            let name = format!("{}[{}]", self.name, idx);
183            Ok(ArrayHandle::new(name, inner))
184        }
185    }
186
187    impl<'a, T> ArrayHandle<'a, HashMap<String, T>> {
188        /// Appends a new inner `HashMap<String, T>` and returns a child
189        /// map handle for populating it.
190        pub fn push_map(&mut self) -> Result<MapHandle<'_, T>, StoreError> {
191            self.data.push(std::collections::HashMap::new());
192            let idx = self.data.len() - 1;
193            let inner = &mut self.data[idx];
194            let name = format!("{}[{}]", self.name, idx);
195            Ok(MapHandle::new(name, inner))
196        }
197    }
198    impl<'a, T> MapHandle<'a, Vec<T>> {
199        /// Inserts a new inner `Vec<T>` under `key` and returns a child
200        /// array handle for populating it.
201        pub fn insert_array<K: Into<String>>(
202            &mut self,
203            key: K,
204        ) -> Result<ArrayHandle<'_, T>, StoreError> {
205            let key = key.into();
206            self.data.insert(key.clone(), Vec::new());
207            let inner = self.data.get_mut(&key).unwrap();
208            let name = format!("{}.{}", self.name, key);
209            Ok(ArrayHandle::new(name, inner))
210        }
211    }
212
213    impl<'a, T> MapHandle<'a, HashMap<String, T>> {
214        /// Inserts a new inner `HashMap<String, T>` under `key` and
215        /// returns a child map handle for populating it.
216        pub fn insert_map<K: Into<String>>(
217            &mut self,
218            key: K,
219        ) -> Result<MapHandle<'_, T>, StoreError> {
220            let key = key.into();
221            self.data
222                .insert(key.clone(), std::collections::HashMap::new());
223            let inner = self.data.get_mut(&key).unwrap();
224            let name = format!("{}.{}", self.name, key);
225            Ok(MapHandle::new(name, inner))
226        }
227    }
228}