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