datastruct_rs/
lib.rs

1pub mod binary_util;
2
3use base64::{engine::general_purpose as base64_engine, Engine as _};
4use binary_util::Binary;
5use serde::{Deserialize, Serialize};
6use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
7use std::collections::HashMap;
8use std::string::ToString;
9
10use nom::{
11    branch::alt,
12    bytes::complete::{escaped, tag, tag_no_case, take_till1, take_while_m_n},
13    character::complete::multispace0,
14    combinator::{map, peek, value as n_value},
15    error::context,
16    multi::separated_list0,
17    number::complete::double,
18    sequence::{delimited, preceded, separated_pair},
19    IResult,
20};
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub enum DValue {
24    /// None
25    None,
26
27    /// String
28    ///
29    /// ```
30    /// use datastruct::DValue;
31    /// DValue::String("hello world".to_string());
32    /// ```
33    String(String),
34
35    /// Number
36    ///
37    /// ```
38    /// use datastruct::DValue;
39    /// DValue::Number(10_f64);
40    /// ```
41    Number(f64),
42
43    /// Boolean
44    ///
45    /// ```
46    /// use datastruct::DValue;
47    /// DValue::Boolean(true);
48    /// ```
49    Boolean(bool),
50
51    /// List
52    ///
53    /// ```
54    /// use datastruct::DValue;
55    /// DValue::List(vec![
56    /// DValue::Number(1.0),
57    /// DValue::Number(2.0),
58    /// DValue::Number(3.0),
59    /// ]);
60    /// ```
61    List(Vec<DValue>),
62
63    /// Dict
64    ///
65    /// ```
66    /// use datastruct::DValue;
67    /// DValue::Dict(std::collections::HashMap::new());
68    /// ```
69    Dict(HashMap<String, DValue>),
70
71    /// Tuple
72    ///
73    /// ```
74    /// use datastruct::DValue;
75    ///
76    /// DValue::Tuple((
77    /// Box::new(DValue::Boolean(true)),
78    /// Box::new(DValue::Boolean(false)),
79    ///
80    /// ));
81    /// ```
82    Tuple((Box<DValue>, Box<DValue>)),
83
84    /// Binary
85    ///
86    /// ```
87    ///
88    /// use datastruct::{DValue ,binary_util::Binary};
89    ///
90    /// DValue::BinaryUtil(Binary::new(vec![72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]));
91    ///
92    /// // or
93    ///
94    ///  let from_b64 = "SGVsbG8gV29ybGQ=".to_string();
95    ///
96    /// DValue::BinaryUtil(Binary::from_b64(from_b64).unwrap());
97    /// ```
98    ///
99    BinaryUtil(Binary),
100}
101
102impl ToString for DValue {
103    fn to_string(&self) -> String {
104        match self {
105            DValue::None => "none".to_string(),
106            DValue::String(str) => format!("\"{}\"", str),
107            DValue::Number(num) => num.to_string(),
108            DValue::Boolean(bool) => match bool {
109                true => "true".to_string(),
110                false => "false".to_string(),
111            },
112            DValue::List(list) => {
113                let elements: Vec<String> = list.iter().map(|v| v.to_string()).collect();
114                format!("[{}]", elements.join(","))
115            }
116            DValue::Dict(dict) => {
117                let entries: Vec<String> = dict
118                    .iter()
119                    .map(|(k, v)| format!("\"{}\":{}", k, v.to_string()))
120                    .collect();
121                format!("{{{}}}", entries.join(","))
122            }
123
124            DValue::Tuple(v) => {
125                format!("({}, {})", v.0.to_string(), v.1.to_string())
126            }
127            DValue::BinaryUtil(val) => val.to_string(),
128        }
129    }
130}
131
132impl Ord for DValue {
133    fn cmp(&self, other: &Self) -> Ordering {
134        self.weight()
135            .partial_cmp(&other.weight())
136            .unwrap_or(Ordering::Equal)
137    }
138}
139
140impl PartialOrd for DValue {
141    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
142        Some(self.cmp(other))
143    }
144}
145
146impl PartialEq for DValue {
147    fn eq(&self, other: &Self) -> bool {
148        self.to_string() == other.to_string()
149    }
150}
151
152impl Eq for DValue {}
153
154impl DValue {
155    pub fn from(data: &str) -> Self {
156        let data = if data.starts_with("b:") && data.ends_with(':') {
157            let base64_content = &data[2..data.len() - 1];
158            match base64_engine::STANDARD.decode(base64_content) {
159                Ok(decoded) => match String::from_utf8(decoded) {
160                    Ok(s) => s,
161                    Err(_) => return Self::None,
162                },
163                Err(_) => return Self::None,
164            }
165        } else {
166            data.to_string()
167        };
168
169        match ValueParser::parse(&data) {
170            Ok((_, v)) => v,
171            Err(_) => Self::None,
172        }
173    }
174
175    pub fn from_json(data: &str) -> Self {
176        serde_json::from_str(data).unwrap_or(Self::None)
177    }
178
179    pub fn to_json(&self) -> String {
180        serde_json::to_string(&self).unwrap_or(String::from("None"))
181    }
182
183    pub fn weight(&self) -> f64 {
184        match self {
185            DValue::Number(num) => *num,
186            DValue::List(items) => items
187                .iter()
188                .map(|item| item.weight())
189                .map(|w| if w == f64::MAX { 0.0 } else { w })
190                .sum(),
191            DValue::Dict(entries) => entries
192                .values()
193                .map(|item| item.weight())
194                .map(|w| if w == f64::MAX { 0.0 } else { w })
195                .sum(),
196
197            DValue::Tuple(v) => {
198                let first_weight = v.0.weight();
199                let second_weight = v.1.weight();
200
201                let first_weight = if first_weight == f64::MAX {
202                    0.0
203                } else {
204                    first_weight
205                };
206                let second_weight = if second_weight == f64::MAX {
207                    0.0
208                } else {
209                    second_weight
210                };
211
212                first_weight + second_weight
213            }
214
215            _ => f64::MAX,
216        }
217    }
218
219    pub fn size(&self) -> usize {
220        match self {
221            DValue::None => 0,
222            DValue::String(str) => str.len(),
223            DValue::Number(_) => 8,
224            DValue::Boolean(_) => 1,
225
226            DValue::List(list) => {
227                let mut result = 0;
228
229                for item in list {
230                    result += item.size();
231                }
232                result
233            }
234            DValue::Dict(dict) => {
235                let mut result = 0;
236                for item in dict {
237                    result += item.1.size();
238                }
239                result
240            }
241            DValue::Tuple(tuple) => tuple.0.size() + tuple.1.size(),
242            DValue::BinaryUtil(bin) => bin.size(),
243        }
244    }
245
246    pub fn datatype(&self) -> String {
247        return match self {
248            DValue::None => "None",
249            DValue::String(_) => "String",
250            DValue::Number(_) => "Number",
251            DValue::Boolean(_) => "Boolean",
252            DValue::List(_) => "List",
253            DValue::Dict(_) => "Dict",
254            DValue::Tuple(_) => "Tuple",
255            DValue::BinaryUtil(_) => "Binary",
256        }
257        .to_string();
258    }
259
260    pub fn as_string(&self) -> Option<String> {
261        return match self {
262            DValue::String(val) => Some(val.to_string()),
263            _ => None,
264        };
265    }
266
267    pub fn as_number(&self) -> Option<f64> {
268        return match self {
269            DValue::Number(val) => Some(*val),
270            _ => None,
271        };
272    }
273
274    pub fn as_bool(&self) -> Option<bool> {
275        return match self {
276            DValue::Boolean(val) => Some(*val),
277            _ => None,
278        };
279    }
280
281    pub fn as_tuple(&self) -> Option<(Box<DValue>, Box<DValue>)> {
282        return match self {
283            DValue::Tuple(val) => Some(val.clone()),
284            _ => None,
285        };
286    }
287
288    pub fn as_list(&self) -> Option<Vec<DValue>> {
289        return match self {
290            DValue::List(val) => Some(val.clone()),
291            _ => None,
292        };
293    }
294
295    pub fn as_dict(&self) -> Option<HashMap<String, DValue>> {
296        return match self {
297            DValue::Dict(val) => Some(val.clone()),
298            _ => None,
299        };
300    }
301}
302
303struct ValueParser {}
304
305impl ValueParser {
306    fn normal(msg: &str) -> IResult<&str, &str> {
307        take_till1(|c: char| c == '\\' || c == '"' || c.is_ascii_control())(msg)
308    }
309
310    fn escapable(i: &str) -> IResult<&str, &str> {
311        context(
312            "escaped",
313            alt((
314                tag("\""),
315                tag("\\"),
316                tag("/"),
317                tag("b"),
318                tag("f"),
319                tag("n"),
320                tag("r"),
321                tag("t"),
322                ValueParser::parse_hex,
323            )),
324        )(i)
325    }
326
327    fn string_format(msg: &str) -> IResult<&str, &str> {
328        escaped(ValueParser::normal, '\\', ValueParser::escapable)(msg)
329    }
330
331    fn parse_hex(msg: &str) -> IResult<&str, &str> {
332        context(
333            "hex string",
334            preceded(
335                peek(tag("u")),
336                take_while_m_n(5, 5, |c: char| c.is_ascii_hexdigit() || c == 'u'),
337            ),
338        )(msg)
339    }
340
341    fn parse_str(msg: &str) -> IResult<&str, &str> {
342        context(
343            "string",
344            alt((
345                tag("\"\""),
346                delimited(tag("\""), ValueParser::string_format, tag("\"")),
347            )),
348        )(msg)
349    }
350
351    fn parse_bin(msg: &str) -> IResult<&str, Binary> {
352        let result: (&str, &str) = context(
353            "binary",
354            alt((
355                tag("binary!()"),
356                delimited(
357                    tag("binary!("),
358                    take_till1(|c: char| c == '\\' || c == ')' || c.is_ascii_control()),
359                    tag(")"),
360                ),
361            )),
362        )(msg)?;
363
364        Ok((
365            result.0,
366            Binary::from_b64(result.1.to_string()).unwrap_or(Binary::new(vec![])),
367        ))
368    }
369
370    fn parse_num(msg: &str) -> IResult<&str, f64> {
371        double(msg)
372    }
373
374    fn parse_bool(msg: &str) -> IResult<&str, bool> {
375        let true_parser = n_value(true, tag_no_case("true"));
376        let false_parser = n_value(false, tag_no_case("false"));
377        alt((true_parser, false_parser))(msg)
378    }
379
380    fn parse_list(msg: &str) -> IResult<&str, Vec<DValue>> {
381        context(
382            "list",
383            delimited(
384                tag("["),
385                separated_list0(
386                    tag(","),
387                    delimited(multispace0, ValueParser::parse, multispace0),
388                ),
389                tag("]"),
390            ),
391        )(msg)
392    }
393
394    fn parse_dict(msg: &str) -> IResult<&str, HashMap<String, DValue>> {
395        context(
396            "object",
397            delimited(
398                tag("{"),
399                map(
400                    separated_list0(
401                        tag(","),
402                        separated_pair(
403                            delimited(multispace0, ValueParser::parse_str, multispace0),
404                            tag(":"),
405                            delimited(multispace0, ValueParser::parse, multispace0),
406                        ),
407                    ),
408                    |tuple_vec: Vec<(&str, DValue)>| {
409                        tuple_vec
410                            .into_iter()
411                            .map(|(k, v)| (String::from(k), v))
412                            .collect()
413                    },
414                ),
415                tag("}"),
416            ),
417        )(msg)
418    }
419
420    fn parse_tuple(msg: &str) -> IResult<&str, (Box<DValue>, Box<DValue>)> {
421        context(
422            "tuple",
423            delimited(
424                tag("("),
425                map(
426                    separated_pair(
427                        delimited(multispace0, ValueParser::parse, multispace0),
428                        tag(","),
429                        delimited(multispace0, ValueParser::parse, multispace0),
430                    ),
431                    |pair: (DValue, DValue)| (Box::new(pair.0), Box::new(pair.1)),
432                ),
433                tag(")"),
434            ),
435        )(msg)
436    }
437
438    fn parse(msg: &str) -> IResult<&str, DValue> {
439        context(
440            "value",
441            delimited(
442                multispace0,
443                alt((
444                    map(ValueParser::parse_num, DValue::Number),
445                    map(ValueParser::parse_bool, DValue::Boolean),
446                    map(ValueParser::parse_str, |s| DValue::String(String::from(s))),
447                    map(ValueParser::parse_list, DValue::List),
448                    map(ValueParser::parse_dict, DValue::Dict),
449                    map(ValueParser::parse_tuple, DValue::Tuple),
450                    map(ValueParser::parse_bin, DValue::BinaryUtil),
451                )),
452                multispace0,
453            ),
454        )(&msg)
455    }
456}
457
458#[cfg(test)]
459mod test {
460
461    use crate::{binary_util::Binary, DValue, ValueParser};
462
463    #[test]
464    fn parse_list() {
465        assert_eq!(
466            ValueParser::parse("[1,2,3,4,5]"),
467            Ok((
468                "",
469                DValue::List(vec![
470                    DValue::Number(1.0),
471                    DValue::Number(2.0),
472                    DValue::Number(3.0),
473                    DValue::Number(4.0),
474                    DValue::Number(5.0),
475                ])
476            ))
477        );
478    }
479
480    #[test]
481    fn parse_tuple() {
482        assert_eq!(
483            ValueParser::parse("(true,1)"),
484            Ok((
485                "",
486                DValue::Tuple((
487                    Box::new(DValue::Boolean(true)),
488                    Box::new(DValue::Number(1_f64))
489                ))
490            ))
491        );
492    }
493
494    #[test]
495    fn parse_binary() {
496        let message = "binary!(bWVtZW50byBtb3Jp)";
497        assert_eq!(
498            ValueParser::parse(message),
499            Ok((
500                "",
501                DValue::BinaryUtil(Binary::new(
502                    [109, 101, 109, 101, 110, 116, 111, 32, 109, 111, 114, 105].to_vec()
503                ))
504            ))
505        )
506    }
507    #[test]
508    fn parse_to_json() {
509        let value = DValue::List(vec![
510            DValue::Number(3.0),
511            DValue::Number(6.0),
512            DValue::Number(9.0),
513        ]);
514        let expected_json = r#"{"List":[{"Number":3.0},{"Number":6.0},{"Number":9.0}]}"#;
515        assert_eq!(value.to_json(), expected_json);
516    }
517}