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,
26
27 String(String),
34
35 Number(f64),
42
43 Boolean(bool),
50
51 List(Vec<DValue>),
62
63 Dict(HashMap<String, DValue>),
70
71 Tuple((Box<DValue>, Box<DValue>)),
83
84 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}