1use std::{collections::HashMap, fmt, marker::PhantomData};
23
24use serde::de::{self, DeserializeOwned, Deserializer, MapAccess, Unexpected, Visitor};
25
26pub(crate) fn parse_bool(raw: &str) -> Result<bool, String> {
32 match raw {
33 "1" | "t" | "T" | "TRUE" | "true" | "True" => Ok(true),
34 "0" | "f" | "F" | "FALSE" | "false" | "False" => Ok(false),
35 other => Err(format!("invalid boolean `{other}`")),
36 }
37}
38
39pub(crate) fn parse_i64(raw: &str) -> Result<i64, String> {
54 let literal = trim_zero_decimal(raw.trim());
55 if let Some(value) = parse_go_int(literal) {
56 return Ok(value);
57 }
58 if is_invalid_octal(literal) {
59 tracing::warn!(
60 "Integer `{raw}` has a leading 0, so it is octal, but it holds an 8 or 9. Reading it as 0, as the \
61 Datadog Agent does."
62 );
63 return Ok(0);
64 }
65 Err(format!("invalid integer `{raw}`"))
66}
67
68fn is_invalid_octal(s: &str) -> bool {
70 let digits = s.strip_prefix(['+', '-']).unwrap_or(s);
71 digits.len() > 1
72 && digits.starts_with('0')
73 && digits.bytes().all(|byte| byte.is_ascii_digit())
74 && digits.bytes().any(|byte| byte >= b'8')
75}
76
77pub(crate) fn parse_decimal_i64(raw: &str) -> Result<i64, String> {
86 trim_zero_fraction(raw.trim())
87 .parse::<i64>()
88 .map_err(|_| format!("invalid integer `{raw}`"))
89}
90
91fn trim_zero_fraction(raw: &str) -> &str {
93 match raw.split_once('.') {
94 Some((integer, fraction)) if !fraction.is_empty() && fraction.bytes().all(|byte| byte == b'0') => integer,
95 _ => raw,
96 }
97}
98
99fn trim_zero_decimal(s: &str) -> &str {
105 let mut found_zero = false;
106 for (index, byte) in s.bytes().enumerate().rev() {
107 match byte {
108 b'.' if found_zero => return &s[..index],
109 b'.' => {}
110 b'0' => found_zero = true,
111 _ => return s,
112 }
113 }
114 s
115}
116
117fn lower(byte: u8) -> u8 {
119 byte | 0x20
120}
121
122fn parse_go_int(s: &str) -> Option<i64> {
124 let (negative, unsigned) = match s.as_bytes().first()? {
125 b'+' => (false, &s[1..]),
126 b'-' => (true, &s[1..]),
127 _ => (false, s),
128 };
129 let magnitude = parse_go_uint(unsigned.as_bytes())?;
130 if negative {
131 i64::try_from(-i128::from(magnitude)).ok()
132 } else {
133 i64::try_from(magnitude).ok()
134 }
135}
136
137fn parse_go_uint(s: &[u8]) -> Option<u64> {
139 let (base, digits) = match s {
140 [b'0', prefix, rest @ ..] if !rest.is_empty() && lower(*prefix) == b'b' => (2, rest),
141 [b'0', prefix, rest @ ..] if !rest.is_empty() && lower(*prefix) == b'o' => (8, rest),
142 [b'0', prefix, rest @ ..] if !rest.is_empty() && lower(*prefix) == b'x' => (16, rest),
143 [b'0', rest @ ..] => (8, rest),
144 [] => return None,
145 _ => (10, s),
146 };
147
148 let mut value: u64 = 0;
149 let mut saw_underscore = false;
150 for &byte in digits {
151 let digit = match byte {
152 b'_' => {
153 saw_underscore = true;
154 continue;
155 }
156 b'0'..=b'9' => byte - b'0',
157 _ if lower(byte).is_ascii_lowercase() => lower(byte) - b'a' + 10,
158 _ => return None,
159 };
160 if digit >= base {
161 return None;
162 }
163 value = value.checked_mul(u64::from(base))?.checked_add(u64::from(digit))?;
164 }
165 if saw_underscore && !underscore_ok(s) {
166 return None;
167 }
168 Some(value)
169}
170
171fn underscore_ok(s: &[u8]) -> bool {
173 #[derive(PartialEq)]
174 enum Last {
175 Start,
176 Digit,
177 Underscore,
178 Other,
179 }
180
181 let s = match s.first() {
182 Some(b'+' | b'-') => &s[1..],
183 _ => s,
184 };
185
186 let mut last = Last::Start;
187 let mut hex = false;
188 let mut rest = s;
189 if let [b'0', prefix, tail @ ..] = s {
190 if matches!(lower(*prefix), b'b' | b'o' | b'x') {
191 last = Last::Digit;
193 hex = lower(*prefix) == b'x';
194 rest = tail;
195 }
196 }
197
198 for &byte in rest {
199 if byte.is_ascii_digit() || (hex && matches!(lower(byte), b'a'..=b'f')) {
200 last = Last::Digit;
201 } else if byte == b'_' {
202 if last != Last::Digit {
203 return false;
204 }
205 last = Last::Underscore;
206 } else if last == Last::Underscore {
207 return false;
208 } else {
209 last = Last::Other;
210 }
211 }
212 last != Last::Underscore
213}
214
215pub(crate) fn parse_f64(raw: &str) -> Result<f64, String> {
225 finite_number(raw, parse_go_float(raw.trim()))
226}
227
228pub(crate) fn parse_decimal_f64(raw: &str) -> Result<f64, String> {
236 finite_number(raw, raw.trim().parse().ok())
237}
238
239fn finite_number(raw: &str, parsed: Option<f64>) -> Result<f64, String> {
241 let parsed = parsed.ok_or_else(|| format!("invalid number `{raw}`"))?;
242 if !parsed.is_finite() {
243 return Err(format!("non-finite number `{raw}`"));
244 }
245 Ok(parsed)
246}
247
248struct FloatLiteral {
251 negative: bool,
252 hex: bool,
253 mantissa: u64,
254 exponent: i64,
256 truncated: bool,
257}
258
259fn parse_go_float(s: &str) -> Option<f64> {
262 let literal = FloatLiteral::read(s.as_bytes())?;
263 if literal.hex {
264 return Some(literal.hex_to_f64());
265 }
266 s.replace('_', "").parse().ok()
268}
269
270impl FloatLiteral {
271 fn read(s: &[u8]) -> Option<Self> {
273 let mut i = 0;
274 let mut negative = false;
275 match s.first() {
276 Some(b'+') => i += 1,
277 Some(b'-') => {
278 negative = true;
279 i += 1;
280 }
281 _ => {}
282 }
283
284 let hex = s.len() > i + 2 && s[i] == b'0' && lower(s[i + 1]) == b'x';
285 let (max_mantissa_digits, exponent_char) = if hex {
286 i += 2;
287 (16, b'p')
288 } else {
289 (19, b'e')
290 };
291 let base: u64 = if hex { 16 } else { 10 };
292
293 let mut underscores = false;
294 let mut saw_dot = false;
295 let mut saw_digits = false;
296 let mut digits = 0;
297 let mut mantissa_digits = 0;
298 let mut mantissa: u64 = 0;
299 let mut truncated = false;
300 let mut dot_position: i64 = 0;
301 while i < s.len() {
302 let byte = s[i];
303 match byte {
304 b'_' => underscores = true,
305 b'.' => {
306 if saw_dot {
307 break;
308 }
309 saw_dot = true;
310 dot_position = digits;
311 }
312 b'0'..=b'9' => {
313 saw_digits = true;
314 if byte == b'0' && digits == 0 {
315 dot_position -= 1;
316 } else {
317 digits += 1;
318 if mantissa_digits < max_mantissa_digits {
319 mantissa = mantissa * base + u64::from(byte - b'0');
320 mantissa_digits += 1;
321 } else if byte != b'0' {
322 truncated = true;
323 }
324 }
325 }
326 _ if hex && matches!(lower(byte), b'a'..=b'f') => {
327 saw_digits = true;
328 digits += 1;
329 if mantissa_digits < max_mantissa_digits {
330 mantissa = mantissa * 16 + u64::from(lower(byte) - b'a' + 10);
331 mantissa_digits += 1;
332 } else {
333 truncated = true;
334 }
335 }
336 _ => break,
337 }
338 i += 1;
339 }
340 if !saw_digits {
341 return None;
342 }
343 if !saw_dot {
344 dot_position = digits;
345 }
346 let mut mantissa_digits = i64::from(mantissa_digits);
347 if hex {
348 dot_position *= 4;
349 mantissa_digits *= 4;
350 }
351
352 if i < s.len() && lower(s[i]) == exponent_char {
353 i += 1;
354 let mut exponent_sign = 1;
355 match s.get(i) {
356 Some(b'+') => i += 1,
357 Some(b'-') => {
358 exponent_sign = -1;
359 i += 1;
360 }
361 _ => {}
362 }
363 if !s.get(i)?.is_ascii_digit() {
364 return None;
365 }
366 let mut exponent: i64 = 0;
367 while let Some(&byte) = s.get(i) {
368 if byte == b'_' {
369 underscores = true;
370 } else if byte.is_ascii_digit() {
371 if exponent < 10_000 {
373 exponent = exponent * 10 + i64::from(byte - b'0');
374 }
375 } else {
376 break;
377 }
378 i += 1;
379 }
380 dot_position += exponent * exponent_sign;
381 } else if hex {
382 return None;
383 }
384
385 if i != s.len() || (underscores && !underscore_ok(s)) {
386 return None;
387 }
388 Some(Self {
389 negative,
390 hex,
391 mantissa,
392 exponent: if mantissa == 0 {
393 0
394 } else {
395 dot_position - mantissa_digits
396 },
397 truncated,
398 })
399 }
400
401 fn hex_to_f64(&self) -> f64 {
404 const MANTISSA_BITS: u32 = 52;
405 const EXPONENT_BIAS: i64 = -1023;
406 const MAX_EXPONENT: i64 = 1023;
407 const MIN_EXPONENT: i64 = EXPONENT_BIAS + 1;
408
409 let mut mantissa = self.mantissa;
410 let mut exponent = self.exponent + i64::from(MANTISSA_BITS);
412
413 while mantissa != 0 && mantissa >> (MANTISSA_BITS + 2) == 0 {
416 mantissa <<= 1;
417 exponent -= 1;
418 }
419 if self.truncated {
420 mantissa |= 1;
421 }
422 while mantissa >> (MANTISSA_BITS + 3) != 0 {
423 mantissa = mantissa >> 1 | (mantissa & 1);
424 exponent += 1;
425 }
426 while mantissa > 1 && exponent < MIN_EXPONENT - 2 {
428 mantissa = mantissa >> 1 | (mantissa & 1);
429 exponent += 1;
430 }
431
432 let mut round = mantissa & 3;
433 mantissa >>= 2;
434 round |= mantissa & 1;
435 exponent += 2;
436 if round == 3 {
437 mantissa += 1;
438 if mantissa == 1 << (MANTISSA_BITS + 1) {
439 mantissa >>= 1;
440 exponent += 1;
441 }
442 }
443 if mantissa >> MANTISSA_BITS == 0 {
444 exponent = EXPONENT_BIAS;
445 }
446 if exponent > MAX_EXPONENT {
447 return if self.negative {
448 f64::NEG_INFINITY
449 } else {
450 f64::INFINITY
451 };
452 }
453
454 let mut bits = mantissa & ((1 << MANTISSA_BITS) - 1);
455 bits |= (((exponent - EXPONENT_BIAS) & 0x7ff) as u64) << MANTISSA_BITS;
456 if self.negative {
457 bits |= 1 << 63;
458 }
459 f64::from_bits(bits)
460 }
461}
462
463pub(crate) fn parse_string_list(raw: &str) -> Vec<String> {
472 match serde_json::from_str::<Option<Vec<Option<String>>>>(raw) {
473 Ok(elements) => elements
474 .unwrap_or_default()
475 .into_iter()
476 .map(Option::unwrap_or_default)
477 .collect(),
478 Err(_) => raw.split_whitespace().map(str::to_owned).collect(),
479 }
480}
481
482pub(crate) fn deserialize_bool<'de, D>(deserializer: D) -> Result<bool, D::Error>
489where
490 D: Deserializer<'de>,
491{
492 deserializer.deserialize_any(BoolVisitor)
493}
494
495pub(crate) fn deserialize_i64<'de, D>(deserializer: D) -> Result<i64, D::Error>
502where
503 D: Deserializer<'de>,
504{
505 deserializer.deserialize_any(I64Visitor)
506}
507
508pub(crate) fn deserialize_f64<'de, D>(deserializer: D) -> Result<f64, D::Error>
515where
516 D: Deserializer<'de>,
517{
518 deserializer.deserialize_any(F64Visitor)
519}
520
521pub(crate) fn deserialize_string<'de, D>(deserializer: D) -> Result<String, D::Error>
527where
528 D: Deserializer<'de>,
529{
530 deserializer.deserialize_any(StringVisitor)
531}
532
533pub(crate) fn deserialize_map_or_json_string<'de, D, T>(deserializer: D) -> Result<T, D::Error>
545where
546 D: Deserializer<'de>,
547 T: DeserializeOwned,
548{
549 struct MapOrJsonString<T>(PhantomData<T>);
550
551 impl<'de, T: DeserializeOwned> Visitor<'de> for MapOrJsonString<T> {
552 type Value = T;
553
554 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
555 f.write_str("a map or a JSON-encoded map string")
556 }
557
558 fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
559 serde_json::from_str(value).map_err(|e| E::custom(format_args!("invalid JSON-encoded map: {e}")))
560 }
561
562 fn visit_map<A: MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
563 T::deserialize(de::value::MapAccessDeserializer::new(map))
564 }
565
566 fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
567 serde_json::from_value(serde_json::Value::Object(serde_json::Map::new())).map_err(E::custom)
568 }
569
570 fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
571 serde_json::from_value(serde_json::Value::Object(serde_json::Map::new())).map_err(E::custom)
572 }
573 }
574
575 deserializer.deserialize_any(MapOrJsonString(PhantomData))
576}
577
578pub(crate) fn deserialize_string_map<'de, D>(deserializer: D) -> Result<HashMap<String, String>, D::Error>
585where
586 D: Deserializer<'de>,
587{
588 let values = deserialize_map_or_json_string::<_, HashMap<String, serde_json::Value>>(deserializer)?;
589 values
590 .into_iter()
591 .map(|(key, value)| {
592 cast_to_string(&value)
593 .map(|value| (key, value))
594 .map_err(de::Error::custom)
595 })
596 .collect()
597}
598
599pub(crate) fn deserialize_number_map<'de, D>(deserializer: D) -> Result<HashMap<String, f64>, D::Error>
605where
606 D: Deserializer<'de>,
607{
608 let values = deserialize_map_or_json_string::<_, HashMap<String, serde_json::Value>>(deserializer)?;
609 values
610 .into_iter()
611 .map(|(key, value)| cast_to_f64(&value).map(|value| (key, value)).map_err(de::Error::custom))
612 .collect()
613}
614
615pub fn cast_to_f64(value: &::serde_json::Value) -> Result<f64, String> {
626 value.deserialize_any(F64Visitor).map_err(|e| e.to_string())
627}
628
629pub fn cast_to_string(value: &::serde_json::Value) -> Result<String, String> {
639 value.deserialize_any(StringVisitor).map_err(|e| e.to_string())
640}
641
642pub(crate) fn deserialize_optional_string<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
648where
649 D: Deserializer<'de>,
650{
651 deserializer.deserialize_option(OptionalStringVisitor)
652}
653
654pub(crate) fn deserialize_optional_i64<'de, D>(deserializer: D) -> Result<Option<i64>, D::Error>
660where
661 D: Deserializer<'de>,
662{
663 deserializer.deserialize_option(OptionalI64Visitor)
664}
665
666struct BoolVisitor;
667
668impl Visitor<'_> for BoolVisitor {
669 type Value = bool;
670
671 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
672 f.write_str("a boolean, a boolean string, or a number")
673 }
674
675 fn visit_bool<E: de::Error>(self, value: bool) -> Result<bool, E> {
676 Ok(value)
677 }
678
679 fn visit_i64<E: de::Error>(self, value: i64) -> Result<bool, E> {
680 Ok(value != 0)
681 }
682
683 fn visit_u64<E: de::Error>(self, value: u64) -> Result<bool, E> {
684 Ok(value != 0)
685 }
686
687 fn visit_f64<E: de::Error>(self, value: f64) -> Result<bool, E> {
688 Ok(value != 0.0)
689 }
690
691 fn visit_str<E: de::Error>(self, value: &str) -> Result<bool, E> {
692 parse_bool(value).map_err(|_| E::invalid_value(Unexpected::Str(value), &self))
693 }
694
695 fn visit_unit<E: de::Error>(self) -> Result<bool, E> {
698 Ok(false)
699 }
700}
701
702struct I64Visitor;
703
704impl Visitor<'_> for I64Visitor {
705 type Value = i64;
706
707 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
708 f.write_str("an integer, a numeric string, or a boolean")
709 }
710
711 fn visit_bool<E: de::Error>(self, value: bool) -> Result<i64, E> {
712 Ok(i64::from(value))
713 }
714
715 fn visit_i64<E: de::Error>(self, value: i64) -> Result<i64, E> {
716 Ok(value)
717 }
718
719 fn visit_u64<E: de::Error>(self, value: u64) -> Result<i64, E> {
720 i64::try_from(value).map_err(|_| E::invalid_value(Unexpected::Unsigned(value), &self))
721 }
722
723 fn visit_f64<E: de::Error>(self, value: f64) -> Result<i64, E> {
725 if !value.is_finite() || value < i64::MIN as f64 || value > i64::MAX as f64 {
726 return Err(E::invalid_value(Unexpected::Float(value), &self));
727 }
728 Ok(value.trunc() as i64)
729 }
730
731 fn visit_str<E: de::Error>(self, value: &str) -> Result<i64, E> {
732 parse_i64(value).map_err(|_| E::invalid_value(Unexpected::Str(value), &self))
733 }
734
735 fn visit_unit<E: de::Error>(self) -> Result<i64, E> {
736 Ok(0)
737 }
738}
739
740struct F64Visitor;
741
742impl Visitor<'_> for F64Visitor {
743 type Value = f64;
744
745 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
746 f.write_str("a number, a numeric string, or a boolean")
747 }
748
749 fn visit_bool<E: de::Error>(self, value: bool) -> Result<f64, E> {
750 Ok(if value { 1.0 } else { 0.0 })
751 }
752
753 fn visit_i64<E: de::Error>(self, value: i64) -> Result<f64, E> {
754 Ok(value as f64)
755 }
756
757 fn visit_u64<E: de::Error>(self, value: u64) -> Result<f64, E> {
758 Ok(value as f64)
759 }
760
761 fn visit_f64<E: de::Error>(self, value: f64) -> Result<f64, E> {
762 Ok(value)
763 }
764
765 fn visit_str<E: de::Error>(self, value: &str) -> Result<f64, E> {
766 parse_f64(value).map_err(|_| E::invalid_value(Unexpected::Str(value), &self))
767 }
768
769 fn visit_unit<E: de::Error>(self) -> Result<f64, E> {
770 Ok(0.0)
771 }
772}
773
774struct StringVisitor;
775
776impl Visitor<'_> for StringVisitor {
777 type Value = String;
778
779 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
780 f.write_str("a string, a boolean, or a number")
781 }
782
783 fn visit_bool<E: de::Error>(self, value: bool) -> Result<String, E> {
784 Ok(value.to_string())
785 }
786
787 fn visit_i64<E: de::Error>(self, value: i64) -> Result<String, E> {
788 Ok(value.to_string())
789 }
790
791 fn visit_u64<E: de::Error>(self, value: u64) -> Result<String, E> {
792 Ok(value.to_string())
793 }
794
795 fn visit_f64<E: de::Error>(self, value: f64) -> Result<String, E> {
798 Ok(value.to_string())
799 }
800
801 fn visit_str<E: de::Error>(self, value: &str) -> Result<String, E> {
802 Ok(value.to_owned())
803 }
804
805 fn visit_string<E: de::Error>(self, value: String) -> Result<String, E> {
806 Ok(value)
807 }
808
809 fn visit_unit<E: de::Error>(self) -> Result<String, E> {
810 Ok(String::new())
811 }
812}
813
814struct OptionalStringVisitor;
815
816impl<'de> Visitor<'de> for OptionalStringVisitor {
817 type Value = Option<String>;
818
819 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
820 f.write_str("a string, a boolean, a number, or null")
821 }
822
823 fn visit_none<E: de::Error>(self) -> Result<Option<String>, E> {
824 Ok(None)
825 }
826
827 fn visit_unit<E: de::Error>(self) -> Result<Option<String>, E> {
828 Ok(None)
829 }
830
831 fn visit_some<D: Deserializer<'de>>(self, deserializer: D) -> Result<Option<String>, D::Error> {
832 deserializer.deserialize_any(StringVisitor).map(Some)
833 }
834}
835
836struct OptionalI64Visitor;
837
838impl<'de> Visitor<'de> for OptionalI64Visitor {
839 type Value = Option<i64>;
840
841 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
842 f.write_str("an integer, a numeric string, a boolean, or null")
843 }
844
845 fn visit_none<E: de::Error>(self) -> Result<Option<i64>, E> {
846 Ok(None)
847 }
848
849 fn visit_unit<E: de::Error>(self) -> Result<Option<i64>, E> {
850 Ok(None)
851 }
852
853 fn visit_some<D: Deserializer<'de>>(self, deserializer: D) -> Result<Option<i64>, D::Error> {
854 deserializer.deserialize_any(I64Visitor).map(Some)
855 }
856}
857
858#[cfg(test)]
860pub(crate) const STRING_LIST_CASES: &[(&str, &[&str])] = &[
861 (r#"["cr-a","cr-b"]"#, &["cr-a", "cr-b"]),
862 (r#"["client_id", "product_id"]"#, &["client_id", "product_id"]),
863 (r#" ["a b","c"] "#, &["a b", "c"]),
864 (r#"["a",null]"#, &["a", ""]),
865 ("[null]", &[""]),
866 ("null", &[]),
867 ("[]", &[]),
868 ("", &[]),
869 (" ", &[]),
870 ("a b", &["a", "b"]),
871 ("a,b", &["a,b"]),
872 ("cr-a cr-b,cr-c", &["cr-a", "cr-b,cr-c"]),
873 ("[a,b]", &["[a,b]"]),
874 (r#"["a",1]"#, &[r#"["a",1]"#]),
875 (r#"{"a":1}"#, &[r#"{"a":1}"#]),
876 (r#""abc""#, &[r#""abc""#]),
877 (r#"["a"] x"#, &[r#"["a"]"#, "x"]),
878 ("a\tb\nc", &["a", "b", "c"]),
879];
880
881#[cfg(test)]
882mod tests {
883 use serde::Deserialize;
884 use serde_json::{json, Value};
885
886 use super::*;
887
888 #[derive(Deserialize)]
889 struct Bool(#[serde(deserialize_with = "deserialize_bool")] bool);
890
891 #[derive(Deserialize)]
892 struct Int(#[serde(deserialize_with = "deserialize_i64")] i64);
893
894 #[derive(Deserialize)]
895 struct Float(#[serde(deserialize_with = "deserialize_f64")] f64);
896
897 #[derive(Deserialize)]
898 struct Str(#[serde(deserialize_with = "deserialize_string")] String);
899
900 #[derive(Deserialize)]
901 struct OptStr(#[serde(deserialize_with = "deserialize_optional_string")] Option<String>);
902
903 #[derive(Deserialize)]
904 struct StringMap(#[serde(deserialize_with = "deserialize_string_map")] HashMap<String, String>);
905
906 #[derive(Deserialize)]
907 struct NumberMap(#[serde(deserialize_with = "deserialize_number_map")] HashMap<String, f64>);
908
909 #[derive(Deserialize)]
910 struct FreeFormMap(
911 #[serde(deserialize_with = "deserialize_map_or_json_string")] ::serde_json::Map<String, ::serde_json::Value>,
912 );
913
914 fn as_bool(value: Value) -> Result<bool, String> {
915 serde_json::from_value::<Bool>(value)
916 .map(|b| b.0)
917 .map_err(|e| e.to_string())
918 }
919
920 fn as_int(value: Value) -> Result<i64, String> {
921 serde_json::from_value::<Int>(value)
922 .map(|i| i.0)
923 .map_err(|e| e.to_string())
924 }
925
926 fn as_float(value: Value) -> Result<f64, String> {
927 serde_json::from_value::<Float>(value)
928 .map(|f| f.0)
929 .map_err(|e| e.to_string())
930 }
931
932 fn as_string(value: Value) -> Result<String, String> {
933 serde_json::from_value::<Str>(value)
934 .map(|s| s.0)
935 .map_err(|e| e.to_string())
936 }
937
938 #[test]
939 fn bool_accepts_every_spelling_go_accepts() {
940 for truthy in [
941 json!(true),
942 json!("true"),
943 json!("True"),
944 json!("TRUE"),
945 json!("t"),
946 json!("T"),
947 json!("1"),
948 ] {
949 assert_eq!(as_bool(truthy.clone()), Ok(true), "{truthy}");
950 }
951 for falsy in [
952 json!(false),
953 json!("false"),
954 json!("False"),
955 json!("FALSE"),
956 json!("f"),
957 json!("F"),
958 json!("0"),
959 ] {
960 assert_eq!(as_bool(falsy.clone()), Ok(false), "{falsy}");
961 }
962
963 assert_eq!(as_bool(json!(2)), Ok(true));
965 assert_eq!(as_bool(json!(-1)), Ok(true));
966 assert_eq!(as_bool(json!(1.0)), Ok(true));
967 assert_eq!(as_bool(json!(0.0)), Ok(false));
968 assert_eq!(as_bool(json!(null)), Ok(false));
969 }
970
971 #[test]
972 fn bool_rejects_what_go_rejects() {
973 for rejected in [json!("yes"), json!("on"), json!(""), json!([true]), json!({"a": true})] {
975 assert!(as_bool(rejected.clone()).is_err(), "{rejected}");
976 }
977 }
978
979 #[test]
980 fn integer_accepts_numeric_strings_floats_and_booleans() {
981 assert_eq!(as_int(json!(8125)), Ok(8125));
982 assert_eq!(as_int(json!("8125")), Ok(8125));
983 assert_eq!(as_int(json!(" -7 ")), Ok(-7));
984 assert_eq!(as_int(json!(true)), Ok(1));
985 assert_eq!(as_int(json!(null)), Ok(0));
986
987 assert_eq!(as_int(json!("8125.0")), Ok(8125));
989 assert_eq!(as_int(json!("8125.000")), Ok(8125));
990 assert_eq!(as_int(json!("-8125.0")), Ok(-8125));
991
992 assert_eq!(as_int(json!(10.9)), Ok(10));
994 assert_eq!(as_int(json!(-10.9)), Ok(-10));
995 }
996
997 #[test]
998 fn integer_rejects_unparseable_and_out_of_range_values() {
999 for rejected in [
1000 json!("8125ms"),
1001 json!(""),
1002 json!("8125.5"),
1003 json!("8125."),
1004 json!(1e300),
1005 json!(["8125"]),
1006 ] {
1007 assert!(as_int(rejected.clone()).is_err(), "{rejected}");
1008 }
1009 }
1010
1011 #[test]
1013 fn integer_string_accepts_exactly_the_go_spellings() {
1014 let accepted: &[(&str, i64)] = &[
1015 ("0x10", 16),
1016 ("0X1F", 31),
1017 ("010", 8),
1018 ("0010", 8),
1019 ("0b11", 3),
1020 ("0B1", 1),
1021 ("0o17", 15),
1022 ("0O7", 7),
1023 ("1_000", 1000),
1024 ("0x_10", 16),
1025 ("0_7", 7),
1026 ("+5", 5),
1027 ("+0x1", 1),
1028 ("-0x10", -16),
1029 ("00", 0),
1030 ("-0", 0),
1031 ("0.0", 0),
1032 ("0x10.0", 16),
1033 ("10.00", 10),
1034 ("-9223372036854775808", i64::MIN),
1035 ("-0x8000000000000000", i64::MIN),
1036 ("9223372036854775807", i64::MAX),
1037 ];
1038 for (raw, expected) in accepted {
1039 assert_eq!(parse_i64(raw), Ok(*expected), "{raw}");
1040 assert_eq!(as_int(json!(raw)), Ok(*expected), "{raw} through the leaf deserializer");
1041 }
1042 }
1043
1044 #[test]
1046 fn integer_string_with_an_invalid_octal_digit_reads_as_zero() {
1047 for raw in [
1048 "08", "09", "-09", "+08", "0128", "00009", "08.0", "08.00", "-08.0", " 08 ",
1049 ] {
1050 assert_eq!(parse_i64(raw), Ok(0), "{raw}");
1051 assert_eq!(as_int(json!(raw)), Ok(0), "{raw} through the leaf deserializer");
1052 }
1053 }
1054
1055 #[test]
1058 fn integer_string_rejects_other_strings_go_rejects() {
1059 for raw in [
1060 "",
1061 "-",
1062 "08.",
1063 "08.5",
1064 "0_8",
1065 "08e1",
1066 "0x8g",
1067 "1__0",
1068 "_1",
1069 "1_",
1070 "0_",
1071 "0x1_",
1072 "0x",
1073 "0b",
1074 "0b2",
1075 "0xg",
1076 "10.50",
1077 "1e3",
1078 "5.",
1079 ".0",
1080 "1.0.0",
1081 "9223372036854775808",
1082 "0x8000000000000000",
1083 "-9223372036854775809",
1084 "+-5",
1085 ] {
1086 assert_eq!(parse_i64(raw), Err(format!("invalid integer `{raw}`")), "{raw}");
1087 }
1088 }
1089
1090 #[test]
1091 fn integer_string_trims_surrounding_whitespace_unlike_go() {
1092 assert_eq!(parse_i64(" 10 "), Ok(10));
1093 assert_eq!(parse_i64("\t0x10\n"), Ok(16));
1094 }
1095
1096 #[test]
1097 fn decimal_integer_keeps_the_saluki_only_grammar() {
1098 let accepted: &[(&str, i64)] = &[
1099 ("010", 10),
1100 ("08", 8),
1101 ("+5", 5),
1102 ("-7", -7),
1103 ("8125.0", 8125),
1104 (" 10 ", 10),
1105 ];
1106 for (raw, expected) in accepted {
1107 assert_eq!(parse_decimal_i64(raw), Ok(*expected), "{raw}");
1108 }
1109 for raw in ["0x10", "0b11", "1_000", "8125.5", "8125.", ""] {
1110 assert_eq!(parse_decimal_i64(raw), Err(format!("invalid integer `{raw}`")), "{raw}");
1111 }
1112 }
1113
1114 #[test]
1115 fn decimal_float_keeps_the_saluki_only_grammar() {
1116 for (raw, expected) in [("1.5", 1.5), ("1e3", 1000.0), (".5", 0.5), (" 2 ", 2.0)] {
1117 assert_eq!(parse_decimal_f64(raw), Ok(expected), "{raw}");
1118 }
1119 for raw in ["0x1p4", "1_000.5", ""] {
1120 assert_eq!(parse_decimal_f64(raw), Err(format!("invalid number `{raw}`")), "{raw}");
1121 }
1122 assert_eq!(parse_decimal_f64("inf"), Err("non-finite number `inf`".to_owned()));
1123 }
1124
1125 #[test]
1127 fn float_string_accepts_go_literals() {
1128 let accepted: &[(&str, f64)] = &[
1129 ("1.5", 1.5),
1130 ("+1.5", 1.5),
1131 ("-1.5", -1.5),
1132 (".5", 0.5),
1133 ("5.", 5.0),
1134 ("010", 10.0),
1135 ("1e3", 1000.0),
1136 ("1_000.5", 1000.5),
1137 ("1e5_0", 1e50),
1138 ("1e-400", 0.0),
1139 ("0x1p4", 16.0),
1140 ("0X1P4", 16.0),
1141 ("-0x1p4", -16.0),
1142 ("0x1.8p1", 3.0),
1143 ("0x.8p1", 1.0),
1144 ("0x1_0p0", 16.0),
1145 ("0x0p0", 0.0),
1146 ];
1147 for (raw, expected) in accepted {
1148 assert_eq!(parse_f64(raw), Ok(*expected), "{raw}");
1149 assert_eq!(
1150 as_float(json!(raw)),
1151 Ok(*expected),
1152 "{raw} through the leaf deserializer"
1153 );
1154 }
1155 }
1156
1157 #[test]
1158 fn float_string_rejects_what_go_or_json_rejects() {
1159 for raw in [
1160 "", ".", "e5", "0x10", "0x1p", "0x1p+", "1_e5", "1__0.5", "_1.5", "1.5_", "1e", "half", "inf", "nan",
1161 "+Inf", "1e400", "0x1p1024",
1162 ] {
1163 assert!(parse_f64(raw).is_err(), "{raw}");
1164 }
1165 }
1166
1167 #[test]
1169 fn hex_float_rounds_like_go() {
1170 let cases: &[(&str, u64)] = &[
1171 ("0x1p-1074", 0x1),
1172 ("0x1p-1075", 0x0),
1173 ("-0x0p0", 0x8000_0000_0000_0000),
1174 ("0x1.fffffffffffffp1023", 0x7fef_ffff_ffff_ffff),
1175 ("0x123456789abcdef01p0", 0x43f2_3456_789a_bcdf),
1176 ("0x1.00000000000008p0", 0x3ff0_0000_0000_0000),
1177 ("0x1.00000000000018p0", 0x3ff0_0000_0000_0002),
1178 ("0x1.0000000000000800000001p0", 0x3ff0_0000_0000_0001),
1179 ("0x1.0000000000000800000p0", 0x3ff0_0000_0000_0000),
1180 ];
1181 for (raw, bits) in cases {
1182 assert_eq!(parse_f64(raw).map(f64::to_bits), Ok(*bits), "{raw}");
1183 }
1184 }
1185
1186 #[test]
1187 fn number_accepts_numeric_strings_integers_and_booleans() {
1188 assert_eq!(as_float(json!(1.5)), Ok(1.5));
1189 assert_eq!(as_float(json!("1.5")), Ok(1.5));
1190 assert_eq!(as_float(json!(2)), Ok(2.0));
1191 assert_eq!(as_float(json!(true)), Ok(1.0));
1192 assert_eq!(as_float(json!(null)), Ok(0.0));
1193 assert!(as_float(json!("half")).is_err());
1194 }
1195
1196 #[test]
1197 fn string_accepts_every_scalar() {
1198 assert_eq!(as_string(json!("datadog_only")), Ok("datadog_only".to_owned()));
1199 assert_eq!(as_string(json!(true)), Ok("true".to_owned()));
1200 assert_eq!(as_string(json!(false)), Ok("false".to_owned()));
1201 assert_eq!(as_string(json!(10485760)), Ok("10485760".to_owned()));
1202 assert_eq!(as_string(json!(-1)), Ok("-1".to_owned()));
1203 assert_eq!(as_string(json!(10.5)), Ok("10.5".to_owned()));
1204 assert_eq!(as_string(json!(null)), Ok(String::new()));
1205
1206 assert_eq!(as_string(json!(1.0)), Ok("1".to_owned()));
1208 }
1209
1210 #[test]
1211 fn string_rejects_compound_values() {
1212 for rejected in [json!(["a"]), json!({"a": "b"})] {
1213 assert!(as_string(rejected.clone()).is_err(), "{rejected}");
1214 }
1215 }
1216
1217 #[test]
1218 fn string_map_coerces_scalar_values() {
1219 let values = serde_json::from_value::<StringMap>(json!({
1220 "bool": true,
1221 "integer": 3,
1222 "null": null,
1223 "string": "datadog_only"
1224 }))
1225 .expect("scalar values deserialize")
1226 .0;
1227
1228 assert_eq!(values["bool"], "true");
1229 assert_eq!(values["integer"], "3");
1230 assert_eq!(values["null"], "");
1231 assert_eq!(values["string"], "datadog_only");
1232 assert!(serde_json::from_value::<StringMap>(json!({ "compound": [] })).is_err());
1233 }
1234
1235 #[test]
1236 fn string_map_accepts_a_json_encoded_string() {
1237 let values = serde_json::from_value::<StringMap>(json!(r#"{"bool": true, "string": "datadog_only"}"#))
1238 .expect("JSON-encoded map deserializes")
1239 .0;
1240
1241 assert_eq!(values["bool"], "true");
1242 assert_eq!(values["string"], "datadog_only");
1243 for rejected in [json!("not json"), json!(r#"["a"]"#), json!(r#"{"compound": []}"#)] {
1244 assert!(
1245 serde_json::from_value::<StringMap>(rejected.clone()).is_err(),
1246 "{rejected}"
1247 );
1248 }
1249 }
1250
1251 #[test]
1252 fn string_map_reads_null_as_empty() {
1253 for empty in [json!(null), json!({})] {
1254 let values = serde_json::from_value::<StringMap>(empty.clone())
1255 .expect("empty map deserializes")
1256 .0;
1257 assert!(values.is_empty(), "{empty}");
1258 }
1259 }
1260
1261 #[test]
1262 fn number_map_coerces_numeric_values() {
1263 let values = serde_json::from_value::<NumberMap>(json!({
1264 "integer": 3,
1265 "float": 0.8,
1266 "string": "0.25"
1267 }))
1268 .expect("numeric values deserialize")
1269 .0;
1270
1271 assert_eq!(values["integer"], 3.0);
1272 assert_eq!(values["float"], 0.8);
1273 assert_eq!(values["string"], 0.25);
1274 assert!(serde_json::from_value::<NumberMap>(json!({ "compound": [] })).is_err());
1275 assert!(serde_json::from_value::<NumberMap>(json!({ "text": "datadog_only" })).is_err());
1276 }
1277
1278 #[test]
1279 fn number_map_accepts_a_json_encoded_string() {
1280 let values = serde_json::from_value::<NumberMap>(json!(r#"{"one": 0.5, "two": 2}"#))
1281 .expect("JSON-encoded map deserializes")
1282 .0;
1283
1284 assert_eq!(values["one"], 0.5);
1285 assert_eq!(values["two"], 2.0);
1286 for rejected in [json!("not json"), json!(r#"["a"]"#), json!(r#"{"compound": []}"#)] {
1287 assert!(
1288 serde_json::from_value::<NumberMap>(rejected.clone()).is_err(),
1289 "{rejected}"
1290 );
1291 }
1292 }
1293
1294 #[test]
1295 fn free_form_map_accepts_a_json_encoded_string() {
1296 let values = serde_json::from_value::<FreeFormMap>(json!(r#"{"svc|op": 0.75}"#))
1297 .expect("JSON-encoded map deserializes")
1298 .0;
1299
1300 assert_eq!(values["svc|op"], json!(0.75));
1301 let parsed = serde_json::from_value::<FreeFormMap>(json!({ "svc|op": 0.75 }))
1303 .expect("parsed map deserializes")
1304 .0;
1305 assert_eq!(parsed["svc|op"], json!(0.75));
1306 for rejected in [json!("not json"), json!(r#"["a"]"#), json!(5)] {
1307 assert!(
1308 serde_json::from_value::<FreeFormMap>(rejected.clone()).is_err(),
1309 "{rejected}"
1310 );
1311 }
1312 }
1313
1314 #[test]
1315 fn optional_string_distinguishes_null_from_a_coerced_scalar() {
1316 let absent = serde_json::from_value::<OptStr>(json!(null))
1317 .expect("null deserializes")
1318 .0;
1319 assert_eq!(absent, None);
1320
1321 let coerced = serde_json::from_value::<OptStr>(json!(3))
1322 .expect("scalar deserializes")
1323 .0;
1324 assert_eq!(coerced, Some("3".to_owned()));
1325 }
1326
1327 #[test]
1328 fn string_list_follows_the_go_slice_cast() {
1329 for (raw, expected) in STRING_LIST_CASES {
1330 assert_eq!(parse_string_list(raw), *expected, "{raw:?}");
1331 }
1332 }
1333}