Skip to main content

prosa_utils/msg/
tvf.rs

1//!
2//! <svg width="40" height="40">
3#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/doc_assets/tvf.svg"))]
4//! </svg>
5//!
6//! Module to define TVF[^tvfnote] message data strcture
7//!
8//! [^tvfnote]: **T**ag **V**alue **F**ormat
9
10use crate::msg::{
11    bytes::Bytes,
12    chrono::{NaiveDate, NaiveDateTime},
13};
14use std::borrow::Cow;
15use std::fmt::Debug;
16use thiserror::Error;
17
18/// Error define for TVF object
19/// Use by several method (serialize/unserialize/getter/setter)
20#[derive(Debug, Eq, Error, PartialOrd, PartialEq)]
21pub enum TvfError {
22    /// Error that indicate the field is not found in the TVF. Missing key
23    #[error("The key `{0}` is not present in the Tvf")]
24    FieldNotFound(usize),
25    /// Error that indicate the field can't be retrieve because the type is not compatible
26    #[error("The type can't be retrieve from the Tvf")]
27    TypeMismatch,
28    /// Error that indicate the field can't be converted due to an other error
29    #[error("The field can't be Converted. {0}")]
30    ConvertionError(String),
31    /// Error encountered during serialization or deserializarion process
32    #[error("Serialization error: {0}")]
33    SerializationError(String),
34}
35
36/// Trait that define a TVF[^tvfnote]
37/// Use to define a key/value object that structure a data
38///
39/// [^tvfnote]: **T**ag **V**alue **F**ormat
40///
41/// ```
42/// use prosa_utils::msg::tvf::Tvf;
43///
44/// fn sample<T: Tvf>(mut tvf: T) {
45///     tvf.put_string(1, "toto");
46///     assert!(tvf.contains(1));
47///     assert_eq!("toto", tvf.get_string(1).unwrap().as_str());
48///
49///     tvf.remove(1);
50///     assert!(!tvf.contains(1));
51/// }
52pub trait Tvf {
53    /// Method to know if the TVF is empty
54    fn is_empty(&self) -> bool;
55    /// Method to know the number of field in the TVF (not recursive)
56    fn len(&self) -> usize;
57
58    /// Method to know is the TVF contain a field the id key
59    fn contains(&self, id: usize) -> bool;
60
61    /// Method to remove a TVF field
62    fn remove(&mut self, id: usize);
63
64    /// Method to convert the TVF into vector ok keys
65    fn into_keys(self) -> Vec<usize>;
66
67    /// Get all the keys for this TVF
68    fn keys(&self) -> Vec<usize>;
69
70    /// Get a sub buffer from a TVF
71    fn get_buffer(&self, id: usize) -> Result<Cow<'_, Self>, TvfError>
72    where
73        Self: Tvf + Clone;
74    /// Get an unsigned value from a TVF
75    fn get_unsigned(&self, id: usize) -> Result<u64, TvfError>;
76    /// Get a signed value from a TVF
77    fn get_signed(&self, id: usize) -> Result<i64, TvfError>;
78    /// Get a byte value from a TVF
79    fn get_byte(&self, id: usize) -> Result<u8, TvfError>;
80    /// Get a float value from a TVF
81    fn get_float(&self, id: usize) -> Result<f64, TvfError>;
82    /// Get a string value from a TVF
83    fn get_string(&self, id: usize) -> Result<Cow<'_, String>, TvfError>;
84    /// Get a buffer of bytes from a TVF
85    fn get_bytes(&self, id: usize) -> Result<Cow<'_, Bytes>, TvfError>;
86    /// Get a date field from a TVF
87    fn get_date(&self, id: usize) -> Result<NaiveDate, TvfError>;
88    /// Get a datetime field from  a TVF.  
89    /// The timestamp is considered to be UTC.
90    fn get_datetime(&self, id: usize) -> Result<NaiveDateTime, TvfError>;
91
92    /// Put a buffer as sub field into a TVF
93    fn put_buffer(&mut self, id: usize, buffer: Self)
94    where
95        Self: Tvf;
96    /// Put an unsigned value to a TVF
97    fn put_unsigned(&mut self, id: usize, unsigned: u64);
98    /// Put a signed value to a TVF
99    fn put_signed(&mut self, id: usize, signed: i64);
100    /// Put a byte into a TVF
101    fn put_byte(&mut self, id: usize, byte: u8);
102    /// Put a float value to a TVF
103    fn put_float(&mut self, id: usize, float: f64);
104    /// Put a string value to a TVF
105    fn put_string<T: Into<String>>(&mut self, id: usize, string: T);
106    /// Put some bytes into a TVF
107    fn put_bytes(&mut self, id: usize, buffer: Bytes);
108    /// Put a date into a TVF
109    fn put_date(&mut self, id: usize, date: NaiveDate);
110    /// Put a datetime into a TVF.  
111    /// The timestamp is considered to be UTC.
112    fn put_datetime(&mut self, id: usize, datetime: NaiveDateTime);
113}
114
115/// Trait to define a TVF[^tvfnote] filter.
116/// Useful to filter sensitive data.
117///
118/// [^tvfnote]: **T**ag **V**alue **F**ormat
119///
120/// ```
121/// use prosa_utils::msg::tvf::{Tvf, TvfFilter};
122/// use prosa_utils::msg::simple_string_tvf::SimpleStringTvf;
123///
124/// enum TvfTestFilter {}
125///
126/// impl TvfFilter for TvfTestFilter {
127///     fn filter<T: Tvf>(mut buf: T) -> T {
128///         buf = <TvfTestFilter as TvfFilter>::mask_tvf_str_field(buf, 1, "*");
129///         <TvfTestFilter as TvfFilter>::mask_tvf_str_field(buf, 2, "0")
130///     }
131/// }
132///
133/// let mut tvf: SimpleStringTvf = Default::default();
134/// tvf.put_string(1, "plain");
135/// tvf.put_string(2, "1234");
136/// tvf.put_string(3, "clear");
137///
138/// let tvf_filtered = TvfTestFilter::filter(tvf);
139/// assert_eq!(Ok(std::borrow::Cow::Owned(String::from("*****"))), tvf_filtered.get_string(1));
140/// assert_eq!(Ok(std::borrow::Cow::Owned(String::from("0000"))), tvf_filtered.get_string(2));
141/// assert_eq!(Ok(std::borrow::Cow::Owned(String::from("clear"))), tvf_filtered.get_string(3));
142/// ```
143pub trait TvfFilter {
144    /// Method to filter the TVF buffer
145    fn filter<T: Tvf>(tvf: T) -> T;
146
147    /// Function to mask a TVF string field
148    ///
149    /// Replace in the TVF buf the string value at the id with a fill character
150    fn mask_tvf_str_field<T: Tvf>(mut tvf: T, id: usize, fill_char: &str) -> T {
151        if tvf.contains(id) {
152            if let Ok(str) = tvf.get_string(id) {
153                tvf.put_string(id, fill_char.repeat(str.len()));
154            } else {
155                // If the field can't be mask, just remove it to prevent any data leak
156                tvf.remove(id);
157            }
158        }
159
160        tvf
161    }
162}