rf_core/
export.rs

1use crate::path::Path;
2use sede::{deserialize_rc_box_any_map, serialize_rc_box_any_map};
3use serde::Deserialize;
4use serde::Serialize;
5use std::any::Any;
6use std::collections::HashMap;
7use std::fmt::{Debug, Display, Formatter};
8use std::rc::Rc;
9use std::str::FromStr;
10
11/// Represents the Result of a query made to the Export.
12pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
13
14/// Abstraction for the result of local computation.
15/// It is an AST decorated with the computation value.
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct Export {
18    #[serde(
19        serialize_with = "serialize_rc_box_any_map",
20        deserialize_with = "deserialize_rc_box_any_map"
21    )]
22    map: HashMap<Path, Rc<Box<dyn Any>>>,
23}
24
25#[macro_export]
26macro_rules! export {
27        ($($x:expr),*) => {{
28            let mut temp_map = std::collections::HashMap::new();
29            $(
30                temp_map.insert($x.0, std::rc::Rc::new(Box::new($x.1) as Box<dyn Any>));
31            )*
32            Export::from(temp_map)
33        }};
34    }
35
36impl Export {
37    /// Create new Export.
38    ///
39    /// # Returns
40    ///
41    /// The new Export.
42    pub fn new() -> Self {
43        Self {
44            map: HashMap::new(),
45        }
46    }
47
48    /// Inserts a value in the Export at the given Path.
49    ///
50    /// # Arguments
51    ///
52    /// * `path` - The Path where to insert the value.
53    /// * `value` - The value to insert.
54    ///
55    /// # Generic Parameters
56    ///
57    /// * `A` - The type of the value to insert. It must have a `'static` lifetime.
58    pub fn put<A: 'static>(&mut self, path: Path, value: A) {
59        self.map.insert(path, Rc::new(Box::new(value)));
60    }
61
62    /// Inserts a value in the Export at the given Path. The value is calculated from the provided
63    /// function.
64    ///
65    /// # Arguments
66    ///
67    /// * `path` - The Path where to insert the value.
68    /// * `fun` - The function from which we calculate the value to insert.
69    ///
70    /// # Generic Parameters
71    ///
72    /// * `A` - The type of the value to insert. It must have a `'static` lifetime.
73    /// * `F` - The type of the function from which the value is calculated.
74    pub fn put_lazy<A: 'static, F>(&mut self, path: Path, fun: F)
75    where
76        F: FnOnce() -> A,
77    {
78        let value = fun();
79        self.put(path, value);
80    }
81
82    /// Inserts a value in the Export at the given Path. The value is calculated from the provided
83    /// function and then returned to the caller.
84    ///
85    /// # Arguments
86    ///
87    /// * `path` - The Path where to insert the value.
88    /// * `fun` - The function from which we calculate the value to insert.
89    ///
90    /// # Generic Parameters
91    ///
92    /// * `A` - The type of the value to insert. It must have a `'static` lifetime.
93    /// * `F` - The type of the function from which the value is calculated.
94    ///
95    /// # Returns
96    ///
97    /// The calculated value.
98    pub fn put_lazy_and_return<A: 'static + Clone, F>(&mut self, path: Path, fun: F) -> A
99    where
100        F: FnOnce() -> A,
101    {
102        let value = fun();
103        self.put(path, value.clone());
104        value
105    }
106
107    /// Returns the value at the given Path.
108    ///
109    /// # Arguments
110    ///
111    /// * `path` - The Path where to get the value.
112    ///
113    /// # Generic Parameters
114    ///
115    /// * `A` - The type of the value to get  to return. It must have a `'static` lifetime.
116    ///
117    /// # Returns
118    ///
119    /// The value at the given Path.
120    pub fn get<A: 'static + FromStr + Clone>(&self, path: &Path) -> Result<A> {
121        let get_result: Result<&A> = self.get_from_map::<A>(path);
122
123        match get_result {
124            Ok(any_val) => Ok(any_val.clone()),
125            _ => {
126                // get deserialized value
127                let str_result = self.get_from_map::<String>(path);
128                str_result?.parse::<A>().map_err(|_| "Cannot parse".into())
129            }
130        }
131    }
132
133    fn get_from_map<A>(&self, path: &Path) -> Result<&A>
134    where
135        A: 'static + FromStr + Clone,
136    {
137        self.map
138            .get(path)
139            .and_then(|value| value.downcast_ref::<A>())
140            .ok_or("No value at the given Path".into())
141    }
142
143    /// Obtain the root value. This function may panic, so it is preferable to use the non-panicking
144    /// counterpart [Export::root_as_result]
145    ///
146    /// # Generic Parameters
147    ///
148    /// * `A` - The type of the value to return. It must have a `'static` lifetime.
149    ///
150    /// # Returns
151    ///
152    /// The root value.
153    ///
154    /// # Panics
155    /// * Panics if there is not a root value (a value at the empty Path).
156    /// * Panics if the type of the root value is not the same as the type of the requested value.
157    pub fn root<A: 'static + FromStr + Clone>(&self) -> A {
158        self.get(&Path::new()).unwrap()
159    }
160
161    /// Obtain the root value. This method is the non-panicking version of [Export::root]
162    ///
163    /// # Generic Parameters
164    ///
165    /// * `A` - The type of the value to return. It must have a `'static` lifetime.
166    ///
167    /// # Returns
168    ///
169    /// A Result containing the root value if present and an error otherwise.
170    pub fn root_as_result<A: 'static + FromStr + Clone>(&self) -> Result<A> {
171        self.get(&Path::new())
172    }
173
174    /// Returns the HashMap of the Export.
175    ///
176    /// # Returns
177    ///
178    /// The HashMap of the Export.
179    pub fn paths(&self) -> &HashMap<Path, Rc<Box<dyn Any>>> {
180        &self.map
181    }
182}
183
184impl Default for Export {
185    fn default() -> Self {
186        Self::new()
187    }
188}
189
190impl From<HashMap<Path, Rc<Box<dyn Any>>>> for Export {
191    fn from(map: HashMap<Path, Rc<Box<dyn Any>>>) -> Self {
192        Self { map }
193    }
194}
195
196impl Display for Export {
197    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
198        let string = serde_json::to_string(&self);
199        write!(f, "{}", string.unwrap())
200    }
201}
202
203impl PartialEq for Export {
204    fn eq(&self, other: &Self) -> bool {
205        let keys_len_equality = self.map.keys().len() == other.map.keys().len();
206
207        let values_equality = self.map.iter().all(|(key, _value)| {
208            if let Ok(value) = self.get::<i32>(key) {
209                if let Ok(other_value) = other.get::<i32>(key) {
210                    value == other_value
211                } else {
212                    false
213                }
214            } else if let Ok(value) = self.get::<bool>(key) {
215                if let Ok(other_value) = other.get::<bool>(key) {
216                    value == other_value
217                } else {
218                    false
219                }
220            } else if let Ok(value) = self.get::<String>(key) {
221                if let Ok(other_value) = other.get::<String>(key) {
222                    value == other_value
223                } else {
224                    false
225                }
226            } else if let Ok(value) = self.get::<f64>(key) {
227                if let Ok(other_value) = other.get::<f64>(key) {
228                    value == other_value
229                } else {
230                    false
231                }
232            } else {
233                false
234            }
235        });
236
237        keys_len_equality && values_equality
238    }
239}
240
241/// This private module is needed to serialize and deserialize the HashMap<Path, Rc<Box<dyn Any>>>.
242mod sede {
243    use crate::path::Path;
244    use serde::de::Visitor;
245    use serde::{Deserializer, Serialize, Serializer};
246    use std::any::Any;
247    use std::collections::HashMap;
248    use std::rc::Rc;
249
250    pub fn serialize_rc_box_any_map<S>(
251        data: &HashMap<Path, Rc<Box<dyn Any>>>,
252        serializer: S,
253    ) -> Result<S::Ok, S::Error>
254    where
255        S: Serializer,
256    {
257        // Serialize the data and wrap it in a HashMap<Path, [u8]>
258        let serializable_data: HashMap<String, String> = data
259            .iter()
260            .map(|(key, value)| {
261                let key_str = serde_json::to_string(key).unwrap();
262                // if value is an i32, cast as String, otherwise panic
263                if let Some(value) = value.downcast_ref::<i32>() {
264                    (key_str, value.clone().to_string())
265                } else if let Some(value) = value.downcast_ref::<bool>() {
266                    (key_str, value.clone().to_string())
267                } else if let Some(value) = value.downcast_ref::<String>() {
268                    (key_str, value.clone())
269                } else if let Some(value) = value.downcast_ref::<f64>() {
270                    (key_str, value.clone().to_string())
271                } else {
272                    panic!("Cannot serialize type")
273                }
274            })
275            .collect();
276        serializable_data.serialize(serializer)
277    }
278
279    struct ExportMapVisitor;
280
281    impl<'de> Visitor<'de> for ExportMapVisitor {
282        type Value = HashMap<Path, Rc<Box<dyn Any>>>;
283        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
284            formatter.write_str("a map of Paths and Any")
285        }
286
287        fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
288        where
289            A: serde::de::MapAccess<'de>,
290        {
291            let mut result = HashMap::new();
292            while let Some((key, value)) = map.next_entry::<String, String>()? {
293                let path: Path = serde_json::from_str(&key).unwrap();
294                let value: Rc<Box<dyn Any>> = Rc::new(Box::new(value) as Box<dyn Any>);
295                result.insert(path, value);
296            }
297            Ok(result)
298        }
299    }
300
301    pub fn deserialize_rc_box_any_map<'de, D>(
302        deserializer: D,
303    ) -> Result<HashMap<Path, Rc<Box<dyn Any>>>, D::Error>
304    where
305        D: Deserializer<'de>,
306    {
307        deserializer.deserialize_map(ExportMapVisitor)
308    }
309}
310
311#[cfg(test)]
312mod tests {
313    use super::*;
314    use crate::path;
315    use crate::path::Path;
316    use crate::slot::Slot::{Nbr, Rep};
317
318    #[test]
319    fn test_new_empty() {
320        let export: Export = Export::new();
321        assert!(export.map.is_empty())
322    }
323
324    #[test]
325    fn test_new() {
326        /* showing how the macros saves us from writing this:
327        let mut map: HashMap<Path, Rc<Box<dyn Any>>> = HashMap::new();
328        map.insert(Path::from(vec![Rep(0), Nbr(0)]), Rc::new(Box::new(10)));
329        let export = Export::from(map);*/
330        let export = export!((path!(Rep(0), Nbr(0)), 10));
331        assert_eq!(export.map.len(), 1);
332    }
333
334    #[test]
335    fn test_put() {
336        let mut export = export!((path!(Rep(0)), 10));
337        export.put(path!(Rep(0), Nbr(0)), 20);
338        export.put(Path::from(vec![Nbr(0)]), "foo");
339        assert_eq!(export.paths().len(), 3);
340    }
341
342    #[test]
343    fn test_get() {
344        let export = export!((path!(Nbr(0), Rep(0)), 10));
345        assert_eq!(
346            //path is written in reverse order in the macro
347            export
348                .get::<i32>(&Path::from(vec![Rep(0), Nbr(0)]))
349                .unwrap(),
350            10
351        );
352    }
353
354    #[test]
355    fn test_get_none() {
356        let export = export!((path!(Rep(0), Nbr(0)), 10));
357        assert!(export
358            .get::<String>(&Path::from(vec![Rep(0), Nbr(0)]))
359            .is_err());
360    }
361
362    #[test]
363    fn test_root() {
364        let export = export!((Path::new(), 10));
365        assert_eq!(export.root::<i32>(), 10);
366    }
367
368    #[test]
369    #[should_panic]
370    fn test_root_panic() {
371        let export = export!((Path::new(), 10));
372        assert_eq!(export.root::<String>(), "foo");
373    }
374
375    #[test]
376    fn test_paths() {
377        let export = export!((Path::new(), 10));
378        let mut map2: HashMap<Path, Rc<Box<dyn Any>>> = HashMap::new();
379        map2.insert(Path::new(), Rc::new(Box::new(10)));
380        assert!(export.map.keys().eq(map2.keys()));
381    }
382
383    #[test]
384    fn test_empty_state() {
385        let export: Export = Export::new();
386        let path = path!(Nbr(0), Rep(0));
387        assert!(export.get::<i32>(&Path::new()).is_err());
388        assert!(export.get::<i32>(&path).is_err());
389    }
390
391    #[test]
392    fn test_root_path() {
393        let mut export: Export = Export::new();
394        export.put(Path::new(), String::from("foo"));
395        assert_eq!(
396            export.get::<String>(&Path::new()).unwrap(),
397            export.root::<String>()
398        );
399        assert_eq!(
400            export.get::<String>(&Path::new()).unwrap(),
401            "foo".to_string()
402        );
403    }
404
405    #[test]
406    fn test_non_root_path() {
407        let mut export: Export = Export::new();
408        let path = path!(Nbr(0), Rep(0));
409        export.put(path.clone(), String::from("bar"));
410        assert_eq!(export.get::<String>(&path).unwrap(), String::from("bar"));
411    }
412
413    #[test]
414    fn test_overwriting_with_different_type() {
415        let mut export: Export = Export::new();
416        export.put(Path::new(), String::from("foo"));
417        assert_eq!(
418            export.get::<String>(&Path::new()).unwrap(),
419            "foo".to_string()
420        );
421        export.put(Path::new(), 77);
422        assert_eq!(export.get::<i32>(&Path::new()).unwrap(), 77);
423    }
424
425    #[test]
426    fn test_put_lazy() {
427        let mut export: Export = Export::new();
428        export.put_lazy(path!(Nbr(0)), || 10);
429        assert_eq!(export.get::<i32>(&path!(Nbr(0))).unwrap(), 10);
430    }
431
432    #[test]
433    fn test_put_lazy_and_return() {
434        let mut export: Export = Export::new();
435        let value = export.put_lazy_and_return(path!(Nbr(0)), || 10);
436        assert_eq!(value, 10);
437        assert_eq!(export.get::<i32>(&path!(Nbr(0))).unwrap(), 10);
438    }
439
440    #[test]
441    fn test_partial_eq() {
442        //assert the equality of two exports
443        let export1 = export!((path!(Rep(0), Nbr(0)), 10));
444        let export2 = export!((path!(Rep(0), Nbr(0)), 10));
445        assert_eq!(export1, export2);
446
447        //assert the inequality of two exports
448        let export3 = export!((path!(Rep(0), Nbr(0)), 100));
449        assert_ne!(export1, export3);
450    }
451
452    #[test]
453    fn test_serialize_and_deserialize() {
454        let export = export![
455            (path!(Rep(0), Nbr(0)), 10),
456            (path!(Nbr(0)), 10),
457            (path!(Rep(0)), 10),
458            (Path::new(), 10)
459        ];
460        let export_ser = serde_json::to_string(&export).unwrap();
461        let export_des: Export = serde_json::from_str(&export_ser).unwrap();
462        assert_eq!(export, export_des);
463    }
464}