prosa_utils/msg/
simple_string_tvf.rs

1//! Implementation of a simple String TVF
2
3use bytes::Bytes;
4use chrono::{NaiveDate, NaiveDateTime};
5
6use crate::msg::tvf::{Tvf, TvfError};
7use std::{borrow::Cow, collections::hash_map::HashMap};
8
9/// Struct that define a simple string TVF
10#[derive(Debug, Default, Clone, PartialEq, Eq)]
11pub struct SimpleStringTvf {
12    fields: HashMap<usize, String>,
13}
14
15static SIMPLE_DATE_FMT: &str = "%Y-%m-%d";
16static SIMPLE_DATETIME_FMT: &str = "%Y-%m-%dT%H:%M:%S";
17
18/// TVF implementation of simple string TVF
19impl Tvf for SimpleStringTvf {
20    /// Test if the TVF is empty (no value in it)
21    ///
22    /// # Examples
23    ///
24    /// ```
25    /// use prosa_utils::msg::tvf::Tvf;
26    /// use prosa_utils::msg::simple_string_tvf::SimpleStringTvf;
27    ///
28    /// let tvf: SimpleStringTvf = Default::default();
29    ///
30    /// assert_eq!(true, tvf.is_empty());
31    /// ```
32    fn is_empty(&self) -> bool {
33        self.fields.is_empty()
34    }
35
36    /// Get the length of the TVF (number of value in it)
37    ///
38    /// # Examples
39    ///
40    /// ```
41    /// use prosa_utils::msg::tvf::Tvf;
42    /// use prosa_utils::msg::simple_string_tvf::SimpleStringTvf;
43    ///
44    /// let mut tvf: SimpleStringTvf = Default::default();
45    /// tvf.put_string(1, String::from("first_val"));
46    /// tvf.put_string(2, String::from("second_val"));
47    ///
48    /// assert_eq!(2, tvf.len());
49    /// ```
50    fn len(&self) -> usize {
51        self.fields.len()
52    }
53
54    fn contains(&self, id: usize) -> bool {
55        self.fields.contains_key(&id)
56    }
57
58    fn remove(&mut self, id: usize) {
59        self.fields.remove(&id);
60    }
61
62    fn into_keys(self) -> Vec<usize> {
63        self.fields.into_keys().collect::<_>()
64    }
65
66    fn keys(&self) -> Vec<usize> {
67        self.fields.keys().cloned().collect()
68    }
69
70    fn get_buffer(&self, id: usize) -> Result<Cow<'_, SimpleStringTvf>, TvfError> {
71        match self.fields.get(&id) {
72            Some(str_value) => Ok(Cow::Owned(SimpleStringTvf::deserialize(str_value)?)),
73            None => Err(TvfError::FieldNotFound(id)),
74        }
75    }
76
77    fn get_unsigned(&self, id: usize) -> Result<u64, TvfError> {
78        match self.fields.get(&id) {
79            Some(str_value) => match str_value.parse::<u64>() {
80                Ok(value) => Ok(value),
81                Err(_) => Err(TvfError::TypeMismatch),
82            },
83            None => Err(TvfError::FieldNotFound(id)),
84        }
85    }
86
87    fn get_signed(&self, id: usize) -> Result<i64, TvfError> {
88        match self.fields.get(&id) {
89            Some(str_value) => match str_value.parse::<i64>() {
90                Ok(value) => Ok(value),
91                Err(_) => Err(TvfError::TypeMismatch),
92            },
93            None => Err(TvfError::FieldNotFound(id)),
94        }
95    }
96
97    fn get_byte(&self, id: usize) -> Result<u8, TvfError> {
98        match self.fields.get(&id) {
99            Some(str_value) => match hex::decode(str_value) {
100                Ok(bytes) => Ok(bytes[0]),
101                Err(_) => Err(TvfError::TypeMismatch),
102            },
103            None => Err(TvfError::FieldNotFound(id)),
104        }
105    }
106
107    fn get_float(&self, id: usize) -> Result<f64, TvfError> {
108        match self.fields.get(&id) {
109            Some(str_value) => match str_value.parse::<f64>() {
110                Ok(value) => Ok(value),
111                Err(_) => Err(TvfError::TypeMismatch),
112            },
113            None => Err(TvfError::FieldNotFound(id)),
114        }
115    }
116
117    fn get_string(&self, id: usize) -> Result<Cow<'_, String>, TvfError> {
118        match self.fields.get(&id) {
119            Some(value) => Ok(Cow::Borrowed(value)),
120            None => Err(TvfError::FieldNotFound(id)),
121        }
122    }
123
124    fn get_bytes(&self, id: usize) -> Result<Cow<'_, Bytes>, TvfError> {
125        match self.fields.get(&id) {
126            Some(str_value) => match hex::decode(str_value) {
127                Ok(bytes) => Ok(Cow::Owned(Bytes::from(bytes))),
128                Err(_) => Err(TvfError::TypeMismatch),
129            },
130            None => Err(TvfError::FieldNotFound(id)),
131        }
132    }
133
134    fn get_date(&self, id: usize) -> Result<NaiveDate, TvfError> {
135        match self.fields.get(&id) {
136            Some(str_value) => match NaiveDate::parse_from_str(str_value, SIMPLE_DATE_FMT) {
137                Ok(d) => Ok(d),
138                Err(e) => Err(TvfError::ConvertionError(e.to_string())),
139            },
140            None => Err(TvfError::FieldNotFound(id)),
141        }
142    }
143
144    fn get_datetime(&self, id: usize) -> Result<NaiveDateTime, TvfError> {
145        match self.fields.get(&id) {
146            Some(str_value) => {
147                match NaiveDateTime::parse_from_str(str_value, SIMPLE_DATETIME_FMT) {
148                    Ok(d) => Ok(d),
149                    Err(e) => Err(TvfError::ConvertionError(e.to_string())),
150                }
151            }
152            None => Err(TvfError::FieldNotFound(id)),
153        }
154    }
155
156    //fn get_datetime_at<T: chrono::Offset + chrono::TimeZone>(&self, id: usize, offset: T) -> Result<chrono::DateTime<T>, TvfError> {
157    //    match self.fields.get(&id) {
158    //        Some(str_value) => match NaiveDateTime::parse_from_str(str_value, SIMPLE_DATETIME_FMT) {
159    //            Ok(d) => Ok(offset.from_utc_datetime(&d)),
160    //            Err(e) => Err(TvfError::ConvertionError(e.to_string()))
161    //        },
162    //        None => Err(TvfError::FieldNotFound(id)),
163    //    }
164    //}
165
166    fn put_buffer(&mut self, id: usize, buffer: SimpleStringTvf) {
167        self.fields.insert(id, buffer.serialize());
168    }
169
170    fn put_unsigned(&mut self, id: usize, unsigned: u64) {
171        self.fields.insert(id, unsigned.to_string());
172    }
173
174    fn put_signed(&mut self, id: usize, signed: i64) {
175        self.fields.insert(id, signed.to_string());
176    }
177
178    fn put_byte(&mut self, id: usize, byte: u8) {
179        let s = hex::encode(vec![byte]);
180        self.fields.insert(id, s);
181    }
182
183    fn put_float(&mut self, id: usize, float: f64) {
184        self.fields.insert(id, float.to_string());
185    }
186
187    fn put_string<T: Into<String>>(&mut self, id: usize, string: T) {
188        self.fields.insert(id, string.into());
189    }
190
191    fn put_bytes(&mut self, id: usize, buffer: bytes::Bytes) {
192        let s = hex::encode(buffer);
193        self.fields.insert(id, s);
194    }
195
196    fn put_date(&mut self, id: usize, date: chrono::NaiveDate) {
197        self.fields
198            .insert(id, date.format(SIMPLE_DATE_FMT).to_string());
199    }
200
201    fn put_datetime(&mut self, id: usize, datetime: chrono::NaiveDateTime) {
202        self.fields
203            .insert(id, datetime.format(SIMPLE_DATETIME_FMT).to_string());
204    }
205
206    //fn put_datetime_tz<T: chrono::Offset + chrono::TimeZone>(&mut self, id: usize, datetime: chrono::DateTime<T>) {
207    //    self.fields.insert(id, datetime.naive_utc().format(SIMPLE_DATETIME_FMT).to_string());
208    //}
209}
210
211impl SimpleStringTvf {
212    /// Serialize this TVF to String
213    pub fn serialize(&self) -> String {
214        let mut out_str = String::new();
215        //let mut writer = BufWriter::new(&out_str);
216
217        for (k, v) in self.fields.iter() {
218            let len = v.len();
219            out_str.push_str(&format!("{k};{len};{v};"));
220        }
221
222        out_str
223    }
224
225    /// Load a TVF from String
226    pub fn deserialize(serial: &str) -> Result<SimpleStringTvf, TvfError> {
227        let mut buffer: SimpleStringTvf = Default::default();
228        let mut w_serial = serial;
229
230        while let Some((k, lv)) = w_serial.split_once(';') {
231            let key = k
232                .parse::<usize>()
233                .map_err(|e| TvfError::SerializationError(e.to_string()))?;
234
235            if let Some((l, rest)) = lv.split_once(';') {
236                let len = l
237                    .parse::<usize>()
238                    .map_err(|e| TvfError::SerializationError(e.to_string()))?;
239                buffer.fields.insert(key, String::from(&rest[0..len]));
240                if rest.chars().nth(len) != Some(';') {
241                    return Err(TvfError::SerializationError(
242                        "Bad field termination char".into(),
243                    ));
244                }
245                w_serial = &rest[len + 1..];
246            } else {
247                return Err(TvfError::SerializationError("No len after key".into()));
248            }
249        }
250
251        Ok(buffer)
252    }
253}
254
255#[cfg(test)]
256mod tests {
257    use crate::msg::tvf::TvfFilter;
258
259    use super::*;
260    use std::fmt::Debug;
261
262    fn test_tvf<T: Tvf + Default + Debug + PartialEq + Clone>(tvf: &mut T) {
263        let mut sub_buffer: T = Default::default();
264        sub_buffer.put_float(200, 154.5);
265        sub_buffer.put_string(201, "Hello rust!");
266        sub_buffer.remove(201);
267        assert!(!sub_buffer.contains(201));
268        sub_buffer.put_string(201, "Hello world!");
269        assert!(sub_buffer.contains(201));
270
271        assert!(tvf.is_empty());
272        tvf.put_unsigned(1, 42);
273        assert_eq!(1, tvf.len());
274        assert!(!tvf.contains(2));
275        tvf.put_string(2, String::from("The great string"));
276        assert!(tvf.contains(2));
277        tvf.put_signed(3, -1);
278        assert_eq!(-1, tvf.get_signed(3).unwrap());
279        tvf.put_float(5, 6.56);
280        tvf.put_byte(6, 32u8);
281        tvf.put_bytes(7, Bytes::from(hex::decode("aabb77ff").unwrap()));
282        tvf.put_date(8, NaiveDate::from_ymd_opt(2023, 6, 5).unwrap());
283        tvf.put_datetime(
284            9,
285            NaiveDate::from_ymd_opt(2023, 6, 5)
286                .unwrap()
287                .and_hms_opt(15, 2, 0)
288                .unwrap(),
289        );
290        tvf.put_buffer(10, sub_buffer.clone());
291        assert_eq!(Err(TvfError::TypeMismatch), tvf.get_unsigned(2));
292        assert_eq!(Err(TvfError::TypeMismatch), tvf.get_signed(2));
293        assert_eq!(Err(TvfError::TypeMismatch), tvf.get_float(2));
294        assert_eq!(Err(TvfError::TypeMismatch), tvf.get_byte(2));
295        assert_eq!(Err(TvfError::TypeMismatch), tvf.get_bytes(2));
296        assert_eq!(
297            Err(TvfError::ConvertionError(
298                "input contains invalid characters".to_string()
299            )),
300            tvf.get_date(2)
301        );
302        assert_eq!(
303            Err(TvfError::ConvertionError(
304                "input contains invalid characters".to_string()
305            )),
306            tvf.get_datetime(2)
307        );
308
309        assert_eq!(Ok(42), tvf.get_unsigned(1));
310        assert_eq!(
311            Ok(Cow::Borrowed(&String::from("The great string"))),
312            tvf.get_string(2)
313        );
314        assert_eq!(Ok(-1), tvf.get_signed(3));
315        assert_eq!(Err(TvfError::FieldNotFound(4)), tvf.get_float(4));
316        assert_eq!(Ok(6.56), tvf.get_float(5));
317        assert_eq!(Ok(32), tvf.get_byte(6));
318        assert_eq!(
319            Ok(Cow::Owned(Bytes::from(hex::decode("aabb77ff").unwrap()))),
320            tvf.get_bytes(7)
321        );
322        assert_eq!(
323            Ok(NaiveDate::parse_from_str("2023-06-05", SIMPLE_DATE_FMT).unwrap()),
324            tvf.get_date(8)
325        );
326        assert_eq!(
327            Ok(NaiveDateTime::parse_from_str("2023-06-05T15:02:00", SIMPLE_DATETIME_FMT).unwrap()),
328            tvf.get_datetime(9)
329        );
330        assert_eq!(Ok(Cow::Owned(sub_buffer)), tvf.get_buffer(10));
331
332        assert_eq!(Err(TvfError::FieldNotFound(100)), tvf.get_unsigned(100));
333        assert_eq!(Err(TvfError::FieldNotFound(110)), tvf.get_signed(110));
334        assert_eq!(Err(TvfError::FieldNotFound(120)), tvf.get_float(120));
335        assert_eq!(Err(TvfError::FieldNotFound(130)), tvf.get_string(130));
336        assert_eq!(Err(TvfError::FieldNotFound(140)), tvf.get_byte(140));
337        assert_eq!(Err(TvfError::FieldNotFound(150)), tvf.get_bytes(150));
338        assert_eq!(Err(TvfError::FieldNotFound(160)), tvf.get_date(160));
339        assert_eq!(Err(TvfError::FieldNotFound(170)), tvf.get_datetime(170));
340        assert_eq!(Err(TvfError::FieldNotFound(180)), tvf.get_buffer(180));
341    }
342
343    #[test]
344    fn test_simple_tvf() {
345        let mut simple_tvf: SimpleStringTvf = Default::default();
346        test_tvf(&mut simple_tvf);
347        assert!(!format!("{simple_tvf:?}").is_empty());
348        let keys = simple_tvf.keys();
349        let into_keys = simple_tvf.clone().into_keys();
350        assert_eq!(keys, into_keys);
351        assert_eq!(9, keys.len());
352        let serial = simple_tvf.serialize();
353        let unserial = SimpleStringTvf::deserialize(&serial).unwrap();
354        assert_eq!(simple_tvf, unserial);
355
356        assert_eq!(
357            Err(TvfError::SerializationError(
358                "invalid digit found in string".into()
359            )),
360            SimpleStringTvf::deserialize("jean;luc")
361        );
362        assert_eq!(
363            Err(TvfError::SerializationError("No len after key".into())),
364            SimpleStringTvf::deserialize("1;")
365        );
366        assert_eq!(
367            Err(TvfError::SerializationError(
368                "invalid digit found in string".into()
369            )),
370            SimpleStringTvf::deserialize("1;jean;")
371        );
372        assert_eq!(
373            Err(TvfError::SerializationError(
374                "Bad field termination char".into()
375            )),
376            SimpleStringTvf::deserialize("1;2;to,")
377        );
378    }
379
380    enum TvfTestFilter {}
381
382    impl TvfFilter for TvfTestFilter {
383        fn filter<T: Tvf>(mut buf: T) -> T {
384            buf = <TvfTestFilter as TvfFilter>::mask_tvf_str_field(buf, 1, "0");
385            buf
386        }
387    }
388
389    #[test]
390    fn test_tvf_filter() {
391        let mut simple_tvf: SimpleStringTvf = Default::default();
392        simple_tvf.put_string(1, "1234");
393        simple_tvf.put_string(2, "1234");
394        assert_eq!(2, simple_tvf.len());
395
396        simple_tvf = TvfTestFilter::filter(simple_tvf);
397        assert_eq!(2, simple_tvf.len());
398        assert_eq!("0000", simple_tvf.get_string(1).unwrap().as_str());
399        assert_eq!("1234", simple_tvf.get_string(2).unwrap().as_str());
400    }
401}