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