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}