calcify/tree/
feedtree.rs

1use std::collections::HashMap;
2use std::error;
3use super::Collection;
4
5use crate::utils;
6use utils::{Serializable, Deserializable};
7use utils::errors::CalcifyError;
8use utils::io::{ToFile,FromFile};
9
10extern crate rmp;
11use rmp::encode::*;
12use rmp::decode::*;
13
14/// Tree of Collections of only a single type, which impl the Feed trait for added functionality
15#[derive(Debug, PartialEq, Clone)]
16pub struct FeedTree<T: Serializable> {
17    metadata: HashMap<String,String>,
18    datafeeds: HashMap<String,Collection<T>>,
19}
20
21impl<T: Serializable> FeedTree<T> {
22    /// Returns new FeedTree
23    ///
24    /// Name and subtype is the only required metadata.
25    /// # Arguments
26    ///
27    /// * `name` - string
28    /// * `subtype` - string, must match given Serializable type
29    ///
30    /// # Example
31    /// ```
32    /// use calcify::FeedTree;
33    /// use calcify::Collection;
34    ///
35    /// let f_col: Collection<f64> = Collection::from(vec![0.0,0.0]);
36    /// let mut ftree: FeedTree<f64> = FeedTree::new("Test_Tree","f64");
37    /// ftree.add_field("Desc", "This is a FeedTree for testing.");
38    /// ftree.add_feed("fcol", f_col);
39    /// ftree.write("fcol", 1.0);
40    /// ftree.write("fcol", 2.0);
41    /// assert_eq!(Collection::from(vec![0.0,0.0,1.0,2.0]),*ftree.get_feed("fcol").unwrap())
42    /// ```
43    pub fn new(name: &str, subtype: &str) -> FeedTree<T> {
44        let mut md = HashMap::new();
45        md.insert(String::from("Name"),String::from(name));
46        md.insert(String::from("SubType"),String::from(subtype));
47        let df = HashMap::new();
48        FeedTree {
49            metadata: md,
50            datafeeds: df,
51        }
52    }
53
54    pub fn add_field(&mut self, key: &str, f: &str) -> Result<(),CalcifyError> {
55        if let Some(_) = self.metadata.insert(String::from(key),String::from(f)) {
56            return Err(CalcifyError::KeyError);
57        }
58        Ok(())
59    }
60
61    /// Inserts new Collection<T> into FeedTree.
62    ///
63    /// # Arguments
64    ///
65    /// * `key` - Hash key, String
66    /// * `f` - Collection<T: Serializable>
67    pub fn add_feed(&mut self, key: &str, f: Collection<T>) -> Result<(),CalcifyError> {
68        if let Some(_) = self.datafeeds.insert(String::from(key),f) {
69            return Err(CalcifyError::KeyError);
70        }
71        Ok(())
72    }
73
74    pub fn get_feed(&mut self, key: &str) -> Option<&Collection<T>> {
75        self.datafeeds.get(key)
76    }
77
78    pub fn write(&mut self, key: &str, data: T) -> Result<(),CalcifyError> {
79        if let Some(feed) = self.datafeeds.get_mut(key) {
80            feed.push(data);
81            Ok(())
82        } else {
83            Err(CalcifyError::KeyError)
84        }
85    }
86}
87
88impl<T: Serializable> Serializable for FeedTree<T> {
89    fn to_json(&self) -> String {
90        let mut out = String::from("{");
91        for (key, val) in &self.metadata {
92            out.push_str(format!("\"{}\":\"{}\",",key,val).as_str());
93        }
94        out.push_str("\"datafeeds\":{");
95        for (key, val) in &self.datafeeds {
96            out.push_str(format!("\"{}\":{},",key,val.to_json()).as_str());
97        }
98        out.pop();
99        out.push_str("}}");
100        out
101    }
102
103    fn to_msg(&self) -> Result<Vec<u8>, ValueWriteError> {
104        let mut buf = Vec::new();
105        write_map_len(&mut buf, (self.metadata.len()+1) as u32)?;
106        for (key, val) in &self.metadata {
107            write_str(&mut buf, key)?;
108            write_str(&mut buf, val)?;
109        }
110        write_str(&mut buf, "datafeeds")?;
111        write_map_len(&mut buf, (self.datafeeds.len()) as u32)?;
112        for (key, val) in &self.datafeeds {
113            write_str(&mut buf, key)?;
114            buf.append(&mut val.to_msg()?);
115        }
116        Ok(buf)
117    }
118}
119
120impl<T: Serializable + Deserializable> Deserializable for FeedTree<T> {
121    fn from_json(s: &str) -> Result<Self, Box<dyn error::Error>> {
122        let mut metadata: HashMap<String,String> = HashMap::new();
123        let mut datafeeds: HashMap<String,Collection<T>> = HashMap::new();
124        for (i,dim) in s.split(",\"datafeeds\":").enumerate() {
125            match i {
126                0 => {
127                    for pair in dim.trim_matches(|p| p == '{' || p == '"' ).split("\",\"") {
128                        let ar: Vec<&str> = pair.split("\":\"").collect();
129                        metadata.insert(String::from(ar[0]),String::from(ar[1]));
130                    }
131                },
132                1 => {
133                    for pair in dim.trim_matches(|p| p == '{' || p == '}' || p == '"' ).split("],\"") {
134                        let ar: Vec<&str> = pair.split("\":").collect();
135                        if let Ok(feed) = Collection::<T>::from_json(&ar[1..].join("\":")){
136                            datafeeds.insert(String::from(ar[0]),feed);
137                        } else {
138                            return Err(Box::new(CalcifyError::ParseError));
139                        }
140                    }
141                },
142                _ => return Err(Box::new(CalcifyError::ParseError)),
143            }
144        }
145        Ok(FeedTree{metadata, datafeeds})
146    }
147
148    fn from_msg(mut bytes: &[u8]) -> Result<(Self,&[u8]), Box<dyn error::Error>> {
149        let mut metadata: HashMap<String,String> = HashMap::new();
150        let mut datafeeds: HashMap<String,Collection<T>> = HashMap::new();
151        if let Ok(len) = read_map_len(&mut bytes) {
152            for _ in 0..len {
153                let mut unparsed: &[u8] = &bytes[..];
154                if let Ok((key,v_rest)) = read_str_from_slice(unparsed) {
155                    match key {
156                        "datafeeds" => {
157                            bytes = v_rest;
158                            break;
159                        },
160                        _ => {
161                            if let Ok((value,rest)) = read_str_from_slice(v_rest) {
162                                unparsed = rest;
163                                metadata.insert(String::from(key),String::from(value));
164                            }
165                        },
166                    }
167
168                }
169                bytes = unparsed;
170            }
171            if let Ok(flen) = read_map_len(&mut bytes) {
172                for _ in 0..flen {
173                    let unparsed: &[u8] = &bytes[..];
174                    if let Ok((key,v_rest)) = read_str_from_slice(unparsed) {
175                        if let Ok((value,rest)) = Collection::<T>::from_msg(v_rest) {
176                            bytes = rest;
177                            datafeeds.insert(String::from(key),value);
178                        }
179                    }
180                }
181            }
182        }
183        Ok((FeedTree{metadata, datafeeds},bytes))
184    }
185}
186
187impl<T: Serializable> ToFile for FeedTree<T>{}
188impl<T: Serializable + Deserializable> FromFile for FeedTree<T>{}
189
190#[cfg(test)]
191mod tests {
192    use super::*;
193    use crate::ThreeVec;
194
195    #[test]
196    fn test_ftree_write() -> Result<(),Box<dyn error::Error>>{
197        let mut col_3v: Collection<ThreeVec> = Collection::empty();
198        for _i in 0..9 {col_3v.push(ThreeVec::new(1.0,2.0,3.0));}
199        let mut ttree = FeedTree::new("Test_Tree","ThreeVec");
200        ttree.add_field("Desc", "This is a Tree for testing.")?;
201        ttree.add_feed("fcol", col_3v)?;
202        ttree.write_msg("./scratch/test_ftree.msg")?;
203        Ok(())
204    }
205
206    #[test]
207    fn test_ftree_read() -> Result<(),Box<dyn error::Error>>{
208        let mut col_3v: Collection<ThreeVec> = Collection::empty();
209        for _i in 0..9 {col_3v.push(ThreeVec::new(1.0,2.0,3.0));}
210        let mut ttree = FeedTree::new("Test_Tree","ThreeVec");
211        ttree.add_field("Desc", "This is a Tree for testing.")?;
212        ttree.add_feed("fcol", col_3v)?;
213
214        let ftree: FeedTree<ThreeVec> = FeedTree::read_msg("./scratch/test_ftree.msg")?;
215        assert_eq!(ftree,ttree);
216        Ok(())
217    }
218
219    #[test]
220    fn test_ftree_json() -> Result<(),Box<dyn error::Error>>{
221        let mut col_3v: Collection<ThreeVec> = Collection::empty();
222        for _i in 0..9 {col_3v.push(ThreeVec::random(1.0));}
223        let mut ttree = FeedTree::new("Test_Tree","ThreeVec");
224        ttree.add_field("Desc", "This is a Tree for testing.")?;
225        ttree.add_feed("fcol", col_3v.clone())?;
226        ttree.add_feed("fcol1", col_3v.clone())?;
227        ttree.add_feed("fcol2", col_3v)?;
228        let pp = ttree.to_json();
229        let oo = FeedTree::<ThreeVec>::from_json(&pp)?;
230        println!("{:?}",oo);
231        Ok(())
232    }
233
234    #[test]
235    fn test_ftree_msg() -> Result<(),Box<dyn error::Error>>{
236        let mut col_3v: Collection<ThreeVec> = Collection::empty();
237        for _i in 0..9 {col_3v.push(ThreeVec::random(1.0));}
238        let mut ttree = FeedTree::new("Test_Tree","ThreeVec");
239        ttree.add_field("Desc", "This is a Tree for testing.")?;
240        ttree.add_feed("fcol", col_3v.clone())?;
241        ttree.add_feed("fcol2", col_3v)?;
242        let pp = ttree.to_msg().unwrap();
243        let (oo,_) = FeedTree::<ThreeVec>::from_msg(&pp).unwrap();
244        assert_eq!(oo,ttree);
245        Ok(())
246    }
247}