1use 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#[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
22impl Tvf for SimpleStringTvf {
24 fn is_empty(&self) -> bool {
37 self.fields.is_empty()
38 }
39
40 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 pub fn serialize(&self) -> String {
204 let mut out_str = String::new();
205 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 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}