Skip to main content

prosa_utils/msg/
simple_string_tvf.rs

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