1use std::{borrow::Cow, str::FromStr};
26
27use bytes::Bytes;
28use rust_decimal::Decimal;
29use serde::{
30 Deserialize, Deserializer, Serialize, Serializer,
31 de::{Error, MapAccess, Unexpected, Visitor, value::MapAccessDeserializer},
32 ser::SerializeSeq,
33};
34use serde_json::value::RawValue;
35use ustr::Ustr;
36
37pub mod decimal;
38
39pub mod sorted_hashset {
43 use ahash::AHashSet;
44 use serde::{Deserialize, Deserializer, Serialize, Serializer};
45
46 pub fn serialize<T, S>(set: &AHashSet<T>, s: S) -> Result<S::Ok, S::Error>
52 where
53 T: Serialize + Ord,
54 S: Serializer,
55 {
56 let mut sorted: Vec<&T> = set.iter().collect();
57 sorted.sort_unstable();
58 sorted.serialize(s)
59 }
60
61 pub fn deserialize<'de, T, D>(d: D) -> Result<AHashSet<T>, D::Error>
67 where
68 T: Deserialize<'de> + Eq + std::hash::Hash,
69 D: Deserializer<'de>,
70 {
71 let vec = Vec::<T>::deserialize(d)?;
72 Ok(vec.into_iter().collect())
73 }
74}
75
76struct DecimalVisitor;
81
82impl<'de> Visitor<'de> for DecimalVisitor {
83 type Value = Decimal;
84
85 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
86 formatter.write_str("a decimal number as string, integer, or float")
87 }
88
89 fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
91 if v.is_empty() {
92 return Ok(Decimal::ZERO);
93 }
94 parse_decimal_str(v).map_err(E::custom)
95 }
96
97 fn visit_string<E: Error>(self, v: String) -> Result<Self::Value, E> {
99 self.visit_str(&v)
100 }
101
102 fn visit_i64<E: Error>(self, v: i64) -> Result<Self::Value, E> {
104 Ok(Decimal::from(v))
105 }
106
107 fn visit_u64<E: Error>(self, v: u64) -> Result<Self::Value, E> {
108 Ok(Decimal::from(v))
109 }
110
111 fn visit_i128<E: Error>(self, v: i128) -> Result<Self::Value, E> {
112 Decimal::try_from_i128_with_scale(v, 0).map_err(E::custom)
113 }
114
115 fn visit_u128<E: Error>(self, v: u128) -> Result<Self::Value, E> {
116 let v = i128::try_from(v).map_err(E::custom)?;
117 Decimal::try_from_i128_with_scale(v, 0).map_err(E::custom)
118 }
119
120 fn visit_f64<E: Error>(self, v: f64) -> Result<Self::Value, E> {
122 if !v.is_finite() {
123 return Err(E::invalid_value(Unexpected::Float(v), &self));
124 }
125 Decimal::try_from(v).map_err(E::custom)
126 }
127
128 fn visit_map<A: MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
129 let number = serde_json::Number::deserialize(MapAccessDeserializer::new(map))?;
130 self.visit_str(&number.to_string())
131 }
132
133 fn visit_unit<E: Error>(self) -> Result<Self::Value, E> {
135 Ok(Decimal::ZERO)
136 }
137
138 fn visit_none<E: Error>(self) -> Result<Self::Value, E> {
139 Ok(Decimal::ZERO)
140 }
141}
142
143struct OptionalDecimalVisitor;
148
149impl<'de> Visitor<'de> for OptionalDecimalVisitor {
150 type Value = Option<Decimal>;
151
152 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
153 formatter.write_str("null or a decimal number as string, integer, or float")
154 }
155
156 fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
159 if v.is_empty() {
160 return Ok(None);
161 }
162 DecimalVisitor.visit_str(v).map(Some)
163 }
164
165 fn visit_string<E: Error>(self, v: String) -> Result<Self::Value, E> {
166 self.visit_str(&v)
167 }
168
169 fn visit_i64<E: Error>(self, v: i64) -> Result<Self::Value, E> {
170 DecimalVisitor.visit_i64(v).map(Some)
171 }
172
173 fn visit_u64<E: Error>(self, v: u64) -> Result<Self::Value, E> {
174 DecimalVisitor.visit_u64(v).map(Some)
175 }
176
177 fn visit_i128<E: Error>(self, v: i128) -> Result<Self::Value, E> {
178 DecimalVisitor.visit_i128(v).map(Some)
179 }
180
181 fn visit_u128<E: Error>(self, v: u128) -> Result<Self::Value, E> {
182 DecimalVisitor.visit_u128(v).map(Some)
183 }
184
185 fn visit_f64<E: Error>(self, v: f64) -> Result<Self::Value, E> {
186 DecimalVisitor.visit_f64(v).map(Some)
187 }
188
189 fn visit_map<A: MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
190 DecimalVisitor.visit_map(map).map(Some)
191 }
192
193 fn visit_unit<E: Error>(self) -> Result<Self::Value, E> {
195 Ok(None)
196 }
197
198 fn visit_none<E: Error>(self) -> Result<Self::Value, E> {
199 Ok(None)
200 }
201}
202
203fn json_token_text(raw: &RawValue) -> serde_json::Result<Cow<'_, str>> {
204 let text = raw.get();
205 if text.starts_with('"') {
206 if let Some(contents) = text
208 .strip_prefix('"')
209 .and_then(|text| text.strip_suffix('"'))
210 && !contents
211 .bytes()
212 .any(|byte| byte < 0x20 || byte == b'"' || byte == b'\\')
213 {
214 return Ok(Cow::Borrowed(contents));
215 }
216 serde_json::from_str::<String>(text).map(Cow::Owned)
217 } else {
218 Ok(Cow::Borrowed(text))
219 }
220}
221
222fn parse_decimal_str(value: &str) -> Result<Decimal, String> {
223 let parsed = if value.contains('e') || value.contains('E') {
224 if value.len() <= Decimal::MAX_SCALE as usize {
225 Decimal::from_scientific(value)
226 } else {
227 decimal::parse(value).or_else(|_| Decimal::from_scientific(value))
228 }
229 } else {
230 Decimal::from_str(value)
231 };
232
233 match parsed {
234 Ok(decimal) => Ok(decimal),
235 Err(e) => decimal_str_rounded(value).ok_or_else(|| e.to_string()),
236 }
237}
238
239fn decimal_str_rounded(value: &str) -> Option<Decimal> {
242 for scale in (0..=Decimal::MAX_SCALE as usize).rev() {
243 let clamped = decimal_string_clamped_to_scale(value, scale)?;
244
245 if let Ok(decimal) = Decimal::from_str(&clamped) {
246 return Some(decimal);
247 }
248 }
249
250 None
251}
252
253fn decimal_string_clamped_to_scale(value: &str, max_scale: usize) -> Option<String> {
254 let (coefficient, exponent) = match value.find(['e', 'E']) {
255 Some(index) => {
256 let exponent = value[index + 1..].parse::<i32>().ok()?;
257 (&value[..index], exponent)
258 }
259 None => (value, 0),
260 };
261
262 let (sign, unsigned) = match coefficient.as_bytes().first()? {
263 b'+' => ("", &coefficient[1..]),
264 b'-' => ("-", &coefficient[1..]),
265 _ => ("", coefficient),
266 };
267 let (integer, fractional) = decimal_components(unsigned)?;
268 let digits = format!("{integer}{fractional}");
269 if decimal_digits_are_zero(&digits, "") {
270 return Some("0".to_string());
271 }
272
273 let point = i32::try_from(integer.len()).ok()?.checked_add(exponent)?;
274
275 if decimal_integer_digits_exceed_max(&digits, point) {
280 return None;
281 }
282
283 let (integer, fractional) = if point <= 0 {
284 let zero_count = usize::try_from(point.checked_neg()?)
287 .ok()?
288 .min(max_scale + 1);
289 (
290 "0".to_string(),
291 format!("{}{digits}", "0".repeat(zero_count)),
292 )
293 } else {
294 let point = usize::try_from(point).ok()?;
295 if point >= digits.len() {
296 (
297 format!("{}{}", digits, "0".repeat(point - digits.len())),
298 String::new(),
299 )
300 } else {
301 (digits[..point].to_string(), digits[point..].to_string())
302 }
303 };
304
305 let (integer, fractional) = round_decimal_components(integer, fractional, max_scale);
306 let sign = if sign == "-" && decimal_digits_are_zero(&integer, &fractional) {
307 ""
308 } else {
309 sign
310 };
311
312 if fractional.is_empty() {
313 Some(format!("{sign}{integer}"))
314 } else {
315 Some(format!("{sign}{integer}.{fractional}"))
316 }
317}
318
319fn decimal_components(value: &str) -> Option<(&str, &str)> {
320 let mut split = value.split('.');
321 let integer = split.next()?;
322 let fractional = split.next().unwrap_or("");
323 if split.next().is_some()
324 || (integer.is_empty() && fractional.is_empty())
325 || !integer.chars().all(|c| c.is_ascii_digit())
326 || !fractional.chars().all(|c| c.is_ascii_digit())
327 {
328 return None;
329 }
330 Some((integer, fractional))
331}
332
333fn decimal_integer_digits_exceed_max(digits: &str, point: i32) -> bool {
334 const DECIMAL_MAX_INTEGER_DIGITS: i32 = 29;
335
336 if point <= 0 {
337 return false;
338 }
339
340 let Some(first_non_zero) = digits.bytes().position(|digit| digit != b'0') else {
341 return false;
342 };
343 let Ok(first_non_zero) = i32::try_from(first_non_zero) else {
344 return true;
345 };
346
347 point.saturating_sub(first_non_zero) > DECIMAL_MAX_INTEGER_DIGITS
348}
349
350fn round_decimal_components(
351 mut integer: String,
352 fractional: String,
353 max_scale: usize,
354) -> (String, String) {
355 if fractional.len() <= max_scale {
356 return (integer, fractional);
357 }
358
359 let mut rounded = fractional.as_bytes()[..max_scale].to_vec();
360 if fractional.as_bytes()[max_scale] >= b'5' {
361 increment_decimal_digits(&mut integer, &mut rounded);
362 }
363
364 (
365 integer,
366 String::from_utf8(rounded).expect("decimal digits are ASCII"),
367 )
368}
369
370fn increment_decimal_digits(integer: &mut String, fractional: &mut [u8]) {
371 for digit in fractional.iter_mut().rev() {
372 if *digit < b'9' {
373 *digit += 1;
374 return;
375 }
376 *digit = b'0';
377 }
378
379 let mut integer_digits = integer.as_bytes().to_vec();
380 for digit in integer_digits.iter_mut().rev() {
381 if *digit < b'9' {
382 *digit += 1;
383 *integer = String::from_utf8(integer_digits).expect("decimal digits are ASCII");
384 return;
385 }
386 *digit = b'0';
387 }
388 integer_digits.insert(0, b'1');
389 *integer = String::from_utf8(integer_digits).expect("decimal digits are ASCII");
390}
391
392fn decimal_digits_are_zero(integer: &str, fractional: &str) -> bool {
393 integer
394 .bytes()
395 .chain(fractional.bytes())
396 .all(|digit| digit == b'0')
397}
398
399pub trait Serializable: Serialize + for<'de> Deserialize<'de> {
401 fn from_json_bytes(data: &[u8]) -> Result<Self, serde_json::Error> {
407 serde_json::from_slice(data)
408 }
409
410 fn to_json_bytes(&self) -> Result<Bytes, serde_json::Error> {
416 serde_json::to_vec(self).map(Bytes::from)
417 }
418}
419
420pub use self::msgpack::{FromMsgPack, MsgPackSerializable, ToMsgPack};
421
422pub mod msgpack {
427 use bytes::Bytes;
428 use serde::{Deserialize, Serialize};
429
430 use super::Serializable;
431
432 pub trait FromMsgPack: for<'de> Deserialize<'de> + Sized {
434 fn from_msgpack_bytes(data: &[u8]) -> Result<Self, rmp_serde::decode::Error> {
440 rmp_serde::from_slice(data)
441 }
442 }
443
444 pub trait ToMsgPack: Serialize {
446 fn to_msgpack_bytes(&self) -> Result<Bytes, rmp_serde::encode::Error> {
452 rmp_serde::to_vec_named(self).map(Bytes::from)
453 }
454 }
455
456 pub trait MsgPackSerializable: Serializable + FromMsgPack + ToMsgPack {}
460
461 impl<T> FromMsgPack for T where T: Serializable {}
462
463 impl<T> ToMsgPack for T where T: Serializable {}
464
465 impl<T> MsgPackSerializable for T where T: Serializable {}
466}
467
468#[must_use]
472pub const fn default_true() -> bool {
473 true
474}
475
476#[must_use]
480pub const fn default_false() -> bool {
481 false
482}
483
484pub fn deserialize_decimal<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
509where
510 D: Deserializer<'de>,
511{
512 deserializer.deserialize_any(DecimalVisitor)
513}
514
515pub fn deserialize_decimal_native<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
530where
531 D: Deserializer<'de>,
532{
533 #[derive(Deserialize)]
534 #[serde(untagged)]
535 enum Value {
536 Decimal(Decimal),
537 Number(serde_json::Number),
538 }
539
540 match Value::deserialize(deserializer)? {
541 Value::Decimal(value) => Ok(value),
542
543 Value::Number(value) => <Decimal as Deserialize>::deserialize(
545 serde::de::value::StringDeserializer::<D::Error>::new(value.to_string()),
546 ),
547 }
548}
549
550pub fn deserialize_optional_decimal<'de, D>(deserializer: D) -> Result<Option<Decimal>, D::Error>
576where
577 D: Deserializer<'de>,
578{
579 deserializer.deserialize_any(OptionalDecimalVisitor)
582}
583
584pub fn deserialize_decimal_token<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
601where
602 D: Deserializer<'de>,
603{
604 deserialize_optional_decimal_token(deserializer)?
605 .ok_or_else(|| D::Error::custom(DECIMAL_TOKEN_MISSING))
606}
607
608pub fn deserialize_optional_decimal_token<'de, D>(
619 deserializer: D,
620) -> Result<Option<Decimal>, D::Error>
621where
622 D: Deserializer<'de>,
623{
624 Option::<Box<RawValue>>::deserialize(deserializer)?
625 .map_or(Ok(None), |raw| parse_decimal_token(&raw))
626}
627
628pub fn deserialize_decimal_token_borrowed<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
640where
641 D: Deserializer<'de>,
642{
643 deserialize_optional_decimal_token_borrowed(deserializer)?
644 .ok_or_else(|| D::Error::custom(DECIMAL_TOKEN_MISSING))
645}
646
647pub fn deserialize_optional_decimal_token_borrowed<'de, D>(
657 deserializer: D,
658) -> Result<Option<Decimal>, D::Error>
659where
660 D: Deserializer<'de>,
661{
662 Option::<&'de RawValue>::deserialize(deserializer)?.map_or(Ok(None), parse_decimal_token)
663}
664
665const DECIMAL_TOKEN_MISSING: &str = "expected a decimal, was null or an empty string";
666
667fn parse_decimal_token<E: Error>(raw: &RawValue) -> Result<Option<Decimal>, E> {
668 let text = json_token_text(raw).map_err(E::custom)?;
669
670 if let Ok(value) = decimal::parse(&text) {
671 return Ok(Some(value));
672 }
673
674 if text.contains(['e', 'E'])
676 && let Some(value) = decimal_str_rounded(&text)
677 {
678 return Ok(Some(value));
679 }
680
681 OptionalDecimalVisitor.visit_str(&text)
682}
683
684pub fn deserialize_decimal_from_str<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
693where
694 D: Deserializer<'de>,
695{
696 let s: std::borrow::Cow<'de, str> = Deserialize::deserialize(deserializer)?;
697 Decimal::from_str(s.as_ref()).map_err(D::Error::custom)
698}
699
700pub fn deserialize_decimal_or_zero<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
708where
709 D: Deserializer<'de>,
710{
711 let s: std::borrow::Cow<'de, str> = Deserialize::deserialize(deserializer)?;
712 if s.is_empty() || s == "0" {
713 Ok(Decimal::ZERO)
714 } else {
715 Decimal::from_str(s.as_ref()).map_err(D::Error::custom)
716 }
717}
718
719pub fn deserialize_optional_decimal_str<'de, D>(
729 deserializer: D,
730) -> Result<Option<Decimal>, D::Error>
731where
732 D: Deserializer<'de>,
733{
734 let s: std::borrow::Cow<'de, str> = Deserialize::deserialize(deserializer)?;
735 if s.is_empty() || s == "0" {
736 Ok(None)
737 } else {
738 Decimal::from_str(s.as_ref())
739 .map(Some)
740 .map_err(D::Error::custom)
741 }
742}
743
744pub fn deserialize_optional_decimal_from_str<'de, D>(
753 deserializer: D,
754) -> Result<Option<Decimal>, D::Error>
755where
756 D: Deserializer<'de>,
757{
758 let opt = Option::<String>::deserialize(deserializer)?;
759 match opt {
760 Some(s) if !s.is_empty() => Decimal::from_str(&s).map(Some).map_err(D::Error::custom),
761 _ => Ok(None),
762 }
763}
764
765pub fn deserialize_optional_decimal_or_zero<'de, D>(deserializer: D) -> Result<Decimal, D::Error>
773where
774 D: Deserializer<'de>,
775{
776 let opt: Option<String> = Deserialize::deserialize(deserializer)?;
777 match opt {
778 None => Ok(Decimal::ZERO),
779 Some(s) if s.is_empty() || s == "0" => Ok(Decimal::ZERO),
780 Some(s) => Decimal::from_str(&s).map_err(D::Error::custom),
781 }
782}
783
784pub fn deserialize_vec_decimal_from_str<'de, D>(deserializer: D) -> Result<Vec<Decimal>, D::Error>
790where
791 D: Deserializer<'de>,
792{
793 let strings = Vec::<String>::deserialize(deserializer)?;
794 strings
795 .into_iter()
796 .map(|s| Decimal::from_str(&s).map_err(D::Error::custom))
797 .collect()
798}
799
800pub fn serialize_decimal_as_str<S>(decimal: &Decimal, serializer: S) -> Result<S::Ok, S::Error>
806where
807 S: Serializer,
808{
809 serializer.serialize_str(&decimal.to_string())
810}
811
812pub fn serialize_optional_decimal_as_str<S>(
818 decimal: &Option<Decimal>,
819 serializer: S,
820) -> Result<S::Ok, S::Error>
821where
822 S: Serializer,
823{
824 match decimal {
825 Some(d) => serializer.serialize_str(&d.to_string()),
826 None => serializer.serialize_none(),
827 }
828}
829
830pub fn serialize_vec_decimal_as_str<S>(
836 decimals: &Vec<Decimal>,
837 serializer: S,
838) -> Result<S::Ok, S::Error>
839where
840 S: Serializer,
841{
842 let mut seq = serializer.serialize_seq(Some(decimals.len()))?;
843 for decimal in decimals {
844 seq.serialize_element(&decimal.to_string())?;
845 }
846 seq.end()
847}
848
849pub fn parse_decimal(s: &str) -> anyhow::Result<Decimal> {
855 Decimal::from_str(s).map_err(|e| anyhow::anyhow!("Failed to parse decimal from '{s}': {e}"))
856}
857
858pub fn parse_optional_decimal(s: &Option<String>) -> anyhow::Result<Option<Decimal>> {
864 match s {
865 None => Ok(None),
866 Some(s) if s.is_empty() => Ok(None),
867 Some(s) => parse_decimal(s).map(Some),
868 }
869}
870
871pub fn deserialize_empty_string_as_none<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
883where
884 D: Deserializer<'de>,
885{
886 let opt = Option::<String>::deserialize(deserializer)?;
887 Ok(opt.filter(|s| !s.is_empty()))
888}
889
890pub fn deserialize_empty_ustr_as_none<'de, D>(deserializer: D) -> Result<Option<Ustr>, D::Error>
896where
897 D: Deserializer<'de>,
898{
899 let opt = Option::<Ustr>::deserialize(deserializer)?;
900 Ok(opt.filter(|s| !s.is_empty()))
901}
902
903pub fn deserialize_string_to_u8<'de, D>(deserializer: D) -> Result<u8, D::Error>
911where
912 D: Deserializer<'de>,
913{
914 let s: std::borrow::Cow<'de, str> = Deserialize::deserialize(deserializer)?;
915 if s.is_empty() {
916 return Ok(0);
917 }
918 s.as_ref().parse::<u8>().map_err(D::Error::custom)
919}
920
921pub fn deserialize_string_to_u64<'de, D>(deserializer: D) -> Result<u64, D::Error>
929where
930 D: Deserializer<'de>,
931{
932 let s: std::borrow::Cow<'de, str> = Deserialize::deserialize(deserializer)?;
933 if s.is_empty() {
934 Ok(0)
935 } else {
936 s.as_ref().parse::<u64>().map_err(D::Error::custom)
937 }
938}
939
940pub fn deserialize_optional_string_to_u64<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
948where
949 D: Deserializer<'de>,
950{
951 let s: Option<String> = Option::deserialize(deserializer)?;
952 match s {
953 Some(s) if s.is_empty() => Ok(None),
954 Some(s) => s.parse().map(Some).map_err(D::Error::custom),
955 None => Ok(None),
956 }
957}
958
959#[cfg(test)]
960mod tests {
961 use ahash::AHashSet;
962 use rstest::*;
963 use rust_decimal::Decimal;
964 use rust_decimal_macros::dec;
965 use serde::{
966 Deserialize, Serialize,
967 de::{Visitor, value::Error as ValueError},
968 };
969 use serde_json::json;
970 use ustr::Ustr;
971
972 use super::{
973 DecimalVisitor, OptionalDecimalVisitor, Serializable, decimal, default_false, default_true,
974 deserialize_decimal, deserialize_decimal_from_str, deserialize_decimal_native,
975 deserialize_decimal_or_zero, deserialize_decimal_token, deserialize_decimal_token_borrowed,
976 deserialize_empty_string_as_none, deserialize_empty_ustr_as_none,
977 deserialize_optional_decimal, deserialize_optional_decimal_or_zero,
978 deserialize_optional_decimal_str, deserialize_optional_decimal_token,
979 deserialize_optional_decimal_token_borrowed, deserialize_optional_string_to_u64,
980 deserialize_string_to_u8, deserialize_string_to_u64, deserialize_vec_decimal_from_str,
981 msgpack::{FromMsgPack, ToMsgPack},
982 parse_decimal, parse_optional_decimal, serialize_decimal_as_str,
983 serialize_optional_decimal_as_str, serialize_vec_decimal_as_str, sorted_hashset,
984 };
985
986 #[derive(Debug, PartialEq, Serialize, Deserialize)]
987 struct SortedSetPayload {
988 #[serde(with = "sorted_hashset")]
989 values: AHashSet<i32>,
990 }
991
992 #[derive(Serialize, Deserialize, PartialEq, Debug)]
993 struct SerializableTestStruct {
994 id: u32,
995 name: String,
996 value: f64,
997 }
998
999 impl Serializable for SerializableTestStruct {}
1000
1001 #[rstest]
1002 #[case("\"")]
1003 #[case("\"1x")]
1004 #[case("\"1\u{e9}")]
1005 #[case("\"1\0")]
1006 #[case("\"1\n")]
1007 #[case("\"1\"\"")]
1008 #[case("\"1\0\"")]
1009 #[case("\"1\n\"")]
1010 fn test_json_decimal_rejects_malformed_raw_strings(#[case] raw: &str) {
1011 let expected = serde_json::from_str::<String>(raw).unwrap_err().to_string();
1013 let deserializer = serde::de::value::MapDeserializer::<_, ValueError>::new(
1014 [("$serde_json::private::RawValue", raw)].into_iter(),
1015 );
1016 let error = decimal::deserialize_json(deserializer).unwrap_err();
1017 assert_eq!(error.to_string(), expected);
1018 }
1019
1020 #[rstest]
1021 #[case("0.125", "0.125", 3)]
1022 #[case("9007199254740993", "9007199254740993", 0)]
1023 #[case("\"1.2500\"", "1.2500", 4)]
1024 #[case(
1025 "\"0.12345678901234567890123456789\"",
1026 "0.1234567890123456789012345679",
1027 28
1028 )]
1029 fn test_native_decimal_preserves_rounding_and_scale(
1030 #[case] token: &str,
1031 #[case] expected: &str,
1032 #[case] scale: u32,
1033 ) {
1034 let direct =
1035 deserialize_decimal_native(&mut serde_json::Deserializer::from_str(token)).unwrap();
1036 let buffered =
1037 deserialize_decimal_native(serde_json::from_str::<serde_json::Value>(token).unwrap())
1038 .unwrap();
1039 let expected = Decimal::from_str_exact(expected).unwrap();
1040
1041 assert_eq!(direct, expected);
1042 assert_eq!(direct.scale(), scale);
1043 assert_eq!(buffered, expected);
1044 assert_eq!(buffered.scale(), scale);
1045 }
1046
1047 #[rstest]
1048 #[case("null")]
1049 #[case("true")]
1050 #[case("\"\"")]
1051 #[case("\"NaN\"")]
1052 #[case("\"79228162514264337593543950336\"")]
1053 fn test_native_decimal_rejects_invalid_values(#[case] token: &str) {
1054 let direct = deserialize_decimal_native(&mut serde_json::Deserializer::from_str(token));
1055 let buffered =
1056 deserialize_decimal_native(serde_json::from_str::<serde_json::Value>(token).unwrap());
1057
1058 assert!(direct.is_err());
1059 assert!(buffered.is_err());
1060 }
1061
1062 #[rstest]
1063 #[case("1.25")]
1064 #[case("2.0")]
1065 #[case("1.2500")]
1066 #[case("-0.0")]
1067 #[case("1e-7")]
1068 #[case("1.5E3")]
1069 #[case("1e-30")]
1070 #[case("1e30")]
1071 #[case("13.223699999999997")]
1072 #[case("9007199254740993")]
1073 #[case("18446744073709551615")]
1074 #[case("-9223372036854775808")]
1075 #[case("\"1.2500\"")]
1076 #[case("\"1e5\"")]
1077 #[case("\"0.12345678901234567890123456789\"")]
1078 #[case("\"79228162514264337593543950336\"")]
1079 #[case("\"not-a-number\"")]
1080 fn test_native_decimal_matches_rust_decimal(#[case] token: &str) {
1081 let value = serde_json::from_str::<serde_json::Value>(token).unwrap();
1082
1083 let fallback = (is_arbitrary_precision() && value.is_number())
1086 .then(|| serde_json::from_value::<Decimal>(serde_json::json!(token)).ok())
1087 .flatten();
1088 let routes = [
1089 (
1090 serde_json::from_str::<Decimal>(token).ok(),
1091 deserialize_decimal_native(&mut serde_json::Deserializer::from_str(token)).ok(),
1092 ),
1093 (
1094 serde_json::from_value::<Decimal>(value.clone()).ok(),
1095 deserialize_decimal_native(value).ok(),
1096 ),
1097 ];
1098
1099 for (native, consolidated) in routes {
1100 let expected = native.or(fallback);
1101 assert_eq!(
1102 consolidated.map(|value| (value, value.scale())),
1103 expected.map(|value| (value, value.scale()))
1104 );
1105 }
1106 }
1107
1108 #[rstest]
1109 #[case("10.0", Decimal::from(10), 0, 1, 0)]
1110 #[case("1.2500", Decimal::new(125, 2), 2, 4, 4)]
1111 #[case("1.25e1", Decimal::new(125, 1), 1, 1, 1)]
1112 fn test_numeric_decimal_preserves_route_scale(
1113 #[case] token: &str,
1114 #[case] expected: Decimal,
1115 #[case] float_scale: u32,
1116 #[case] token_scale: u32,
1117 #[case] buffered_token_scale: u32,
1118 ) {
1119 let arbitrary_precision = is_arbitrary_precision();
1120
1121 let scale = if arbitrary_precision {
1122 token_scale
1123 } else {
1124 float_scale
1125 };
1126
1127 let buffered_scale = if arbitrary_precision {
1128 buffered_token_scale
1129 } else {
1130 float_scale
1131 };
1132
1133 let direct = deserialize_decimal(&mut serde_json::Deserializer::from_str(token)).unwrap();
1134 let buffered =
1135 deserialize_decimal(serde_json::from_str::<serde_json::Value>(token).unwrap()).unwrap();
1136 let quoted = deserialize_decimal(serde_json::Value::String("1.2500".to_string())).unwrap();
1137 assert_eq!(direct, expected);
1138 assert_eq!(direct.scale(), scale);
1139 assert_eq!(buffered, expected);
1140 assert_eq!(buffered.scale(), buffered_scale);
1141 assert_eq!(quoted, Decimal::new(12500, 4));
1142 assert_eq!(quoted.scale(), 4);
1143 }
1144
1145 fn is_arbitrary_precision() -> bool {
1146 serde_json::from_str::<serde_json::Number>("1.2500")
1147 .unwrap()
1148 .to_string()
1149 == "1.2500"
1150 }
1151
1152 #[rstest]
1153 fn test_sorted_hashset_serialization_is_deterministic() {
1154 let payload = SortedSetPayload {
1155 values: [29, 3, 17, 5, 23, 11].into_iter().collect(),
1156 };
1157
1158 let encoded = serde_json::to_string(&payload).unwrap();
1159 let expected = serde_json::to_string(&json!({ "values": [3, 5, 11, 17, 23, 29] })).unwrap();
1160 let restored: SortedSetPayload = serde_json::from_str(&encoded).unwrap();
1161
1162 assert_eq!(encoded, expected);
1163 assert_eq!(restored, payload);
1164 }
1165
1166 #[rstest]
1167 fn test_serializable_json_roundtrip() {
1168 let original = SerializableTestStruct {
1169 id: 42,
1170 name: "test".to_string(),
1171 value: std::f64::consts::PI,
1172 };
1173
1174 let json_bytes = original.to_json_bytes().unwrap();
1175 let deserialized = SerializableTestStruct::from_json_bytes(&json_bytes).unwrap();
1176
1177 assert_eq!(original, deserialized);
1178 }
1179
1180 #[rstest]
1181 fn test_serializable_msgpack_roundtrip() {
1182 let original = SerializableTestStruct {
1183 id: 123,
1184 name: "msgpack_test".to_string(),
1185 value: std::f64::consts::E,
1186 };
1187
1188 let msgpack_bytes = original.to_msgpack_bytes().unwrap();
1189 let deserialized = SerializableTestStruct::from_msgpack_bytes(&msgpack_bytes).unwrap();
1190
1191 assert_eq!(original, deserialized);
1192 }
1193
1194 #[rstest]
1195 fn test_serializable_json_invalid_data() {
1196 let invalid_json = b"invalid json data";
1197 let result = SerializableTestStruct::from_json_bytes(invalid_json);
1198 assert!(result.is_err());
1199 }
1200
1201 #[rstest]
1202 fn test_serializable_msgpack_invalid_data() {
1203 let invalid_msgpack = b"invalid msgpack data";
1204 let result = SerializableTestStruct::from_msgpack_bytes(invalid_msgpack);
1205 assert!(result.is_err());
1206 }
1207
1208 #[rstest]
1209 fn test_serializable_json_empty_values() {
1210 let test_struct = SerializableTestStruct {
1211 id: 0,
1212 name: String::new(),
1213 value: 0.0,
1214 };
1215
1216 let json_bytes = test_struct.to_json_bytes().unwrap();
1217 let deserialized = SerializableTestStruct::from_json_bytes(&json_bytes).unwrap();
1218
1219 assert_eq!(test_struct, deserialized);
1220 }
1221
1222 #[rstest]
1223 fn test_serializable_msgpack_empty_values() {
1224 let test_struct = SerializableTestStruct {
1225 id: 0,
1226 name: String::new(),
1227 value: 0.0,
1228 };
1229
1230 let msgpack_bytes = test_struct.to_msgpack_bytes().unwrap();
1231 let deserialized = SerializableTestStruct::from_msgpack_bytes(&msgpack_bytes).unwrap();
1232
1233 assert_eq!(test_struct, deserialized);
1234 }
1235
1236 #[derive(Deserialize)]
1237 struct TestOptionalDecimalStr {
1238 #[serde(deserialize_with = "deserialize_optional_decimal_str")]
1239 value: Option<Decimal>,
1240 }
1241
1242 #[derive(Deserialize)]
1243 struct TestDecimalOrZero {
1244 #[serde(deserialize_with = "deserialize_decimal_or_zero")]
1245 value: Decimal,
1246 }
1247
1248 #[derive(Deserialize)]
1249 struct TestOptionalDecimalOrZero {
1250 #[serde(deserialize_with = "deserialize_optional_decimal_or_zero")]
1251 value: Decimal,
1252 }
1253
1254 #[derive(Serialize, Deserialize, PartialEq, Debug)]
1255 struct TestDecimalRoundtrip {
1256 #[serde(
1257 serialize_with = "serialize_decimal_as_str",
1258 deserialize_with = "deserialize_decimal_from_str"
1259 )]
1260 value: Decimal,
1261 #[serde(
1262 serialize_with = "serialize_optional_decimal_as_str",
1263 deserialize_with = "super::deserialize_optional_decimal_from_str"
1264 )]
1265 optional_value: Option<Decimal>,
1266 }
1267
1268 #[rstest]
1269 #[case(r#"{"value":"123.45"}"#, Some(dec!(123.45)))]
1270 #[case(r#"{"value":"0"}"#, None)]
1271 #[case(r#"{"value":""}"#, None)]
1272 fn test_deserialize_optional_decimal_str(
1273 #[case] json: &str,
1274 #[case] expected: Option<Decimal>,
1275 ) {
1276 let result: TestOptionalDecimalStr = serde_json::from_str(json).unwrap();
1277 assert_eq!(result.value, expected);
1278 }
1279
1280 #[rstest]
1281 fn test_deserialize_optional_decimal_from_str_empty_is_none() {
1282 let json = r#"{"value": "1.5", "optional_value": ""}"#;
1283 let result: TestDecimalRoundtrip = serde_json::from_str(json).unwrap();
1284 assert_eq!(result.optional_value, None);
1285 }
1286
1287 #[rstest]
1288 #[case(r#"{"value":"123.45"}"#, dec!(123.45))]
1289 #[case(r#"{"value":"0"}"#, Decimal::ZERO)]
1290 #[case(r#"{"value":""}"#, Decimal::ZERO)]
1291 fn test_deserialize_decimal_or_zero(#[case] json: &str, #[case] expected: Decimal) {
1292 let result: TestDecimalOrZero = serde_json::from_str(json).unwrap();
1293 assert_eq!(result.value, expected);
1294 }
1295
1296 #[rstest]
1297 #[case(r#"{"value":"123.45"}"#, dec!(123.45))]
1298 #[case(r#"{"value":"0"}"#, Decimal::ZERO)]
1299 #[case(r#"{"value":null}"#, Decimal::ZERO)]
1300 #[case(r#"{"value":""}"#, Decimal::ZERO)]
1301 fn test_deserialize_optional_decimal_or_zero(#[case] json: &str, #[case] expected: Decimal) {
1302 let result: TestOptionalDecimalOrZero = serde_json::from_str(json).unwrap();
1303 assert_eq!(result.value, expected);
1304 }
1305
1306 #[rstest]
1307 fn test_decimal_serialization_roundtrip() {
1308 let original = TestDecimalRoundtrip {
1309 value: dec!(123.456789012345678),
1310 optional_value: Some(dec!(0.000000001)),
1311 };
1312
1313 let json = serde_json::to_string(&original).unwrap();
1314
1315 assert!(json.contains("\"123.456789012345678\""));
1317 assert!(json.contains("\"0.000000001\""));
1318
1319 let deserialized: TestDecimalRoundtrip = serde_json::from_str(&json).unwrap();
1320 assert_eq!(original.value, deserialized.value);
1321 assert_eq!(original.optional_value, deserialized.optional_value);
1322 }
1323
1324 #[rstest]
1325 fn test_decimal_optional_none_handling() {
1326 let test_struct = TestDecimalRoundtrip {
1327 value: dec!(42.0),
1328 optional_value: None,
1329 };
1330
1331 let json = serde_json::to_string(&test_struct).unwrap();
1332 assert!(json.contains("null"));
1333
1334 let parsed: TestDecimalRoundtrip = serde_json::from_str(&json).unwrap();
1335 assert_eq!(test_struct.value, parsed.value);
1336 assert_eq!(None, parsed.optional_value);
1337 }
1338
1339 #[derive(Deserialize)]
1340 struct TestEmptyStringAsNone {
1341 #[serde(deserialize_with = "deserialize_empty_string_as_none")]
1342 value: Option<String>,
1343 }
1344
1345 #[rstest]
1346 #[case(r#"{"value":"hello"}"#, Some("hello".to_string()))]
1347 #[case(r#"{"value":""}"#, None)]
1348 #[case(r#"{"value":null}"#, None)]
1349 fn test_deserialize_empty_string_as_none(#[case] json: &str, #[case] expected: Option<String>) {
1350 let result: TestEmptyStringAsNone = serde_json::from_str(json).unwrap();
1351 assert_eq!(result.value, expected);
1352 }
1353
1354 #[derive(Deserialize)]
1355 struct TestEmptyUstrAsNone {
1356 #[serde(deserialize_with = "deserialize_empty_ustr_as_none")]
1357 value: Option<Ustr>,
1358 }
1359
1360 #[rstest]
1361 #[case(r#"{"value":"hello"}"#, Some(Ustr::from("hello")))]
1362 #[case(r#"{"value":""}"#, None)]
1363 #[case(r#"{"value":null}"#, None)]
1364 fn test_deserialize_empty_ustr_as_none(#[case] json: &str, #[case] expected: Option<Ustr>) {
1365 let result: TestEmptyUstrAsNone = serde_json::from_str(json).unwrap();
1366 assert_eq!(result.value, expected);
1367 }
1368
1369 #[derive(Serialize, Deserialize, PartialEq, Debug)]
1370 struct TestVecDecimal {
1371 #[serde(
1372 serialize_with = "serialize_vec_decimal_as_str",
1373 deserialize_with = "deserialize_vec_decimal_from_str"
1374 )]
1375 values: Vec<Decimal>,
1376 }
1377
1378 #[rstest]
1379 fn test_vec_decimal_roundtrip() {
1380 let original = TestVecDecimal {
1381 values: vec![dec!(1.5), dec!(2.25), dec!(100.001)],
1382 };
1383
1384 let json = serde_json::to_string(&original).unwrap();
1385 assert!(json.contains("[\"1.5\",\"2.25\",\"100.001\"]"));
1386
1387 let parsed: TestVecDecimal = serde_json::from_str(&json).unwrap();
1388 assert_eq!(original.values, parsed.values);
1389 }
1390
1391 #[rstest]
1392 fn test_vec_decimal_empty() {
1393 let original = TestVecDecimal { values: vec![] };
1394
1395 let json = serde_json::to_string(&original).unwrap();
1396 let parsed: TestVecDecimal = serde_json::from_str(&json).unwrap();
1397 assert_eq!(original.values, parsed.values);
1398 }
1399
1400 #[derive(Deserialize)]
1401 struct TestStringToU8 {
1402 #[serde(deserialize_with = "deserialize_string_to_u8")]
1403 value: u8,
1404 }
1405
1406 #[rstest]
1407 #[case(r#"{"value":"42"}"#, 42)]
1408 #[case(r#"{"value":"0"}"#, 0)]
1409 #[case(r#"{"value":"255"}"#, 255)]
1410 #[case(r#"{"value":""}"#, 0)]
1411 fn test_deserialize_string_to_u8(#[case] json: &str, #[case] expected: u8) {
1412 let result: TestStringToU8 = serde_json::from_str(json).unwrap();
1413 assert_eq!(result.value, expected);
1414 }
1415
1416 #[rstest]
1417 #[case(r#"{"value":"256"}"#)]
1418 #[case(r#"{"value":"999"}"#)]
1419 #[case(r#"{"value":"abc"}"#)]
1420 fn test_deserialize_string_to_u8_invalid(#[case] json: &str) {
1421 let result: Result<TestStringToU8, _> = serde_json::from_str(json);
1422 assert!(result.is_err());
1423 }
1424
1425 #[derive(Deserialize)]
1426 struct TestStringToU64 {
1427 #[serde(deserialize_with = "deserialize_string_to_u64")]
1428 value: u64,
1429 }
1430
1431 #[rstest]
1432 #[case(r#"{"value":"12345678901234"}"#, 12_345_678_901_234)]
1433 #[case(r#"{"value":"0"}"#, 0)]
1434 #[case(r#"{"value":"18446744073709551615"}"#, u64::MAX)]
1435 #[case(r#"{"value":""}"#, 0)]
1436 fn test_deserialize_string_to_u64(#[case] json: &str, #[case] expected: u64) {
1437 let result: TestStringToU64 = serde_json::from_str(json).unwrap();
1438 assert_eq!(result.value, expected);
1439 }
1440
1441 #[rstest]
1442 #[case(r#"{"value":"18446744073709551616"}"#)]
1443 #[case(r#"{"value":"abc"}"#)]
1444 #[case(r#"{"value":"-1"}"#)]
1445 fn test_deserialize_string_to_u64_invalid(#[case] json: &str) {
1446 let result: Result<TestStringToU64, _> = serde_json::from_str(json);
1447 assert!(result.is_err());
1448 }
1449
1450 #[derive(Deserialize)]
1451 struct TestOptionalStringToU64 {
1452 #[serde(deserialize_with = "deserialize_optional_string_to_u64")]
1453 value: Option<u64>,
1454 }
1455
1456 #[rstest]
1457 #[case(r#"{"value":"12345678901234"}"#, Some(12_345_678_901_234))]
1458 #[case(r#"{"value":"0"}"#, Some(0))]
1459 #[case(r#"{"value":""}"#, None)]
1460 #[case(r#"{"value":null}"#, None)]
1461 fn test_deserialize_optional_string_to_u64(#[case] json: &str, #[case] expected: Option<u64>) {
1462 let result: TestOptionalStringToU64 = serde_json::from_str(json).unwrap();
1463 assert_eq!(result.value, expected);
1464 }
1465
1466 #[rstest]
1467 #[case("123.45", dec!(123.45))]
1468 #[case("0", Decimal::ZERO)]
1469 #[case("0.0", Decimal::ZERO)]
1470 fn test_parse_decimal(#[case] input: &str, #[case] expected: Decimal) {
1471 let result = parse_decimal(input).unwrap();
1472 assert_eq!(result, expected);
1473 }
1474
1475 #[rstest]
1476 fn test_parse_decimal_invalid() {
1477 assert!(parse_decimal("invalid").is_err());
1478 assert!(parse_decimal("").is_err());
1479 }
1480
1481 #[rstest]
1482 #[case(&Some("123.45".to_string()), Some(dec!(123.45)))]
1483 #[case(&Some("0".to_string()), Some(Decimal::ZERO))]
1484 #[case(&Some(String::new()), None)]
1485 #[case(&None, None)]
1486 fn test_parse_optional_decimal(
1487 #[case] input: &Option<String>,
1488 #[case] expected: Option<Decimal>,
1489 ) {
1490 let result = parse_optional_decimal(input).unwrap();
1491 assert_eq!(result, expected);
1492 }
1493
1494 #[derive(Debug, Serialize, Deserialize, PartialEq)]
1497 struct TestFlexibleDecimal {
1498 #[serde(
1499 serialize_with = "decimal::serialize",
1500 deserialize_with = "deserialize_decimal"
1501 )]
1502 value: Decimal,
1503 #[serde(
1504 serialize_with = "decimal::serialize_optional",
1505 deserialize_with = "deserialize_optional_decimal"
1506 )]
1507 optional_value: Option<Decimal>,
1508 }
1509
1510 #[rstest]
1511 #[case(r#"{"value": 123.456, "optional_value": 789.012}"#, dec!(123.456), Some(dec!(789.012)))]
1512 #[case(r#"{"value": "123.456", "optional_value": "789.012"}"#, dec!(123.456), Some(dec!(789.012)))]
1513 #[case(r#"{"value": 1.25e-3, "optional_value": 2.5e2}"#, dec!(0.00125), Some(dec!(250)))]
1514 #[case(r#"{"value": 100, "optional_value": null}"#, dec!(100), None)]
1515 #[case(r#"{"value": null, "optional_value": null}"#, Decimal::ZERO, None)]
1516 fn test_deserialize_flexible_decimal(
1517 #[case] json: &str,
1518 #[case] expected_value: Decimal,
1519 #[case] expected_optional: Option<Decimal>,
1520 ) {
1521 let result: TestFlexibleDecimal = serde_json::from_str(json).unwrap();
1522 assert_eq!(result.value, expected_value);
1523 assert_eq!(result.optional_value, expected_optional);
1524 }
1525
1526 #[rstest]
1527 fn test_flexible_decimal_roundtrip() {
1528 let original = TestFlexibleDecimal {
1529 value: dec!(123.456),
1530 optional_value: Some(dec!(789.012)),
1531 };
1532
1533 let json = serde_json::to_string(&original).unwrap();
1534 let deserialized: TestFlexibleDecimal = serde_json::from_str(&json).unwrap();
1535
1536 assert_eq!(original.value, deserialized.value);
1537 assert_eq!(original.optional_value, deserialized.optional_value);
1538 }
1539
1540 #[rstest]
1541 fn test_flexible_decimal_scientific_notation() {
1542 let json = r#"{"value": 0.00000001, "optional_value": 12345678.12345}"#;
1546 let parsed: TestFlexibleDecimal = serde_json::from_str(json).unwrap();
1547 assert_eq!(parsed.value, dec!(0.00000001));
1548 assert_eq!(parsed.optional_value, Some(dec!(12345678.12345)));
1549 }
1550
1551 #[rstest]
1552 fn test_flexible_decimal_empty_string_optional() {
1553 let json = r#"{"value": 100, "optional_value": ""}"#;
1554 let parsed: TestFlexibleDecimal = serde_json::from_str(json).unwrap();
1555 assert_eq!(parsed.value, dec!(100));
1556 assert_eq!(parsed.optional_value, None);
1557 }
1558
1559 #[derive(Debug, Deserialize)]
1560 struct TestDecimalToken {
1561 #[serde(deserialize_with = "deserialize_decimal_token")]
1562 value: Decimal,
1563 #[serde(default, deserialize_with = "deserialize_optional_decimal_token")]
1564 optional_value: Option<Decimal>,
1565 }
1566
1567 #[derive(Debug, Deserialize)]
1568 struct TestDecimalTokenBorrowed {
1569 #[serde(deserialize_with = "deserialize_decimal_token_borrowed")]
1570 value: Decimal,
1571 #[serde(
1572 default,
1573 deserialize_with = "deserialize_optional_decimal_token_borrowed"
1574 )]
1575 optional_value: Option<Decimal>,
1576 }
1577
1578 #[rstest]
1579 #[case(r#"{"value": 100000000.123456789}"#, "100000000.123456789", None)]
1580 #[case(
1581 r#"{"value": 100000000.123456788, "optional_value": null}"#,
1582 "100000000.123456788",
1583 None
1584 )]
1585 #[case(r#"{"value": "0.10", "optional_value": ""}"#, "0.10", None)]
1586 #[case(
1587 r#"{"value": 18446744073709551617, "optional_value": 0.30000000000000004}"#,
1588 "18446744073709551617",
1589 Some("0.30000000000000004")
1590 )]
1591 #[case(
1592 r#"{"value": 1.1403e-4, "optional_value": "2.5e2"}"#,
1593 "0.00011403",
1594 Some("250")
1595 )]
1596 #[case(
1597 r#"{"value": 5.551115123125783e-17}"#,
1598 "0.0000000000000000555111512313",
1599 None
1600 )]
1601 #[case(r#"{"value": 0.00000000000000000000000000001e28}"#, "0.1", None)]
1602 #[case(
1603 r#"{"value": 0.000000000000000000000000000012345678901234567890123456789e28}"#,
1604 "0.1234567890123456789012345679",
1605 None
1606 )]
1607 #[case(
1608 r#"{"value": 0.12345678901234567890123456789}"#,
1609 "0.1234567890123456789012345679",
1610 None
1611 )]
1612 #[case(
1613 r#"{"value": "-7.50", "optional_value": -0.001}"#,
1614 "-7.50",
1615 Some("-0.001")
1616 )]
1617 fn test_deserialize_decimal_token(
1618 #[case] json: &str,
1619 #[case] expected_value: &str,
1620 #[case] expected_optional: Option<&str>,
1621 ) {
1622 let result: TestDecimalToken = serde_json::from_str(json).unwrap();
1623 let borrowed: TestDecimalTokenBorrowed = serde_json::from_str(json).unwrap();
1624
1625 assert_eq!(result.value.to_string(), expected_value);
1626 assert_eq!(
1627 result
1628 .optional_value
1629 .map(|value| value.to_string())
1630 .as_deref(),
1631 expected_optional
1632 );
1633 assert_eq!(borrowed.value.to_string(), expected_value);
1634 assert_eq!(
1635 borrowed
1636 .optional_value
1637 .map(|value| value.to_string())
1638 .as_deref(),
1639 expected_optional
1640 );
1641 }
1642
1643 #[rstest]
1644 fn test_deserialize_decimal_token_keeps_decimals_that_collapse_in_f64() {
1645 let first: TestDecimalToken =
1646 serde_json::from_str(r#"{"value": 100000000.123456789}"#).unwrap();
1647 let second: TestDecimalToken =
1648 serde_json::from_str(r#"{"value": 100000000.123456788}"#).unwrap();
1649 let first_f64 = "100000000.123456789".parse::<f64>().unwrap();
1650 let second_f64 = "100000000.123456788".parse::<f64>().unwrap();
1651
1652 assert_eq!(first_f64.to_bits(), second_f64.to_bits());
1653 assert_eq!(first.value, dec!(100000000.123456789));
1654 assert_eq!(second.value, dec!(100000000.123456788));
1655 }
1656
1657 #[rstest]
1658 #[case(r#"{"value": null}"#)]
1659 #[case(r#"{"value": ""}"#)]
1660 #[case(r#"{"value": "abc"}"#)]
1661 #[case(r#"{"value": true}"#)]
1662 #[case(r#"{"value": {}}"#)]
1663 #[case(r#"{"value": [1]}"#)]
1664 #[case(r#"{"value": 1e400}"#)]
1665 #[case(r#"{"value": 79228162514264337593543950336}"#)]
1666 #[case(r#"{"value": 1, "optional_value": "abc"}"#)]
1667 #[case(r#"{"optional_value": 1}"#)]
1668 fn test_deserialize_decimal_token_rejects_invalid(#[case] json: &str) {
1669 assert!(serde_json::from_str::<TestDecimalToken>(json).is_err());
1670 assert!(serde_json::from_str::<TestDecimalTokenBorrowed>(json).is_err());
1671 }
1672
1673 #[rstest]
1674 fn test_deserialize_decimal_token_borrowed_requires_borrowed_input() {
1675 let json = r#"{"value": 1.25}"#;
1676 let value: serde_json::Value = serde_json::from_str(json).unwrap();
1677
1678 let from_slice: TestDecimalTokenBorrowed = serde_json::from_slice(json.as_bytes()).unwrap();
1679 let from_reader =
1680 serde_json::from_reader::<_, TestDecimalTokenBorrowed>(json.as_bytes()).unwrap_err();
1681 let from_value = serde_json::from_value::<TestDecimalTokenBorrowed>(value).unwrap_err();
1682
1683 assert_eq!(from_slice.value, dec!(1.25));
1684 assert_eq!(
1685 from_reader.to_string(),
1686 "invalid type: string \"1.25\", expected raw value at line 1 column 15"
1687 );
1688 assert_eq!(
1689 from_value.to_string(),
1690 "invalid type: string \"1.25\", expected raw value"
1691 );
1692 }
1693
1694 #[rstest]
1695 fn test_deserialize_decimal_token_buffered_value_renders_number() {
1696 let value = json!({"value": 65000.5, "optional_value": "0.10"});
1697
1698 let result: TestDecimalToken = serde_json::from_value(value).unwrap();
1699
1700 assert_eq!(result.value.to_string(), "65000.5");
1701 assert_eq!(
1702 result
1703 .optional_value
1704 .map(|value| value.to_string())
1705 .as_deref(),
1706 Some("0.10")
1707 );
1708 }
1709
1710 #[rstest]
1711 fn test_deserialize_decimal_token_rejects_tagged_enum_buffer() {
1712 #[derive(Debug, Deserialize)]
1713 #[serde(tag = "type")]
1714 #[allow(dead_code, reason = "the test only checks that decoding fails")]
1715 enum Tagged {
1716 Token(TestDecimalToken),
1717 }
1718
1719 let result = serde_json::from_str::<Tagged>(r#"{"type": "Token", "value": 1.5}"#);
1720
1721 assert!(result.is_err());
1722 }
1723
1724 #[derive(Debug, Deserialize)]
1727 struct TestDecimalOnly {
1728 #[serde(deserialize_with = "deserialize_decimal")]
1729 value: Decimal,
1730 }
1731
1732 #[rstest]
1733 #[case("0.12345678901234567890123456789e1", dec!(1.2345678901234567890123456789))]
1734 #[case("-0.12345678901234567890123456789E1", dec!(-1.2345678901234567890123456789))]
1735 #[case("0.00000000000000000000000000001e1", dec!(0.0000000000000000000000000001))]
1736 fn test_deserialize_decimal_scientific_representable(
1737 #[case] value: &str,
1738 #[case] expected: Decimal,
1739 #[values(false, true)] optional: bool,
1740 ) {
1741 let json = serde_json::to_string(&json!({"value": value})).unwrap();
1742
1743 let actual = if optional {
1744 serde_json::from_str::<TestOptionalDecimalOnly>(&json)
1745 .unwrap()
1746 .value
1747 } else {
1748 Some(
1749 serde_json::from_str::<TestDecimalOnly>(&json)
1750 .unwrap()
1751 .value,
1752 )
1753 };
1754
1755 assert_eq!(actual, Some(expected));
1756 }
1757
1758 #[rstest]
1759 #[case(23, 28, 23)]
1760 #[case(24, 29, 0)]
1761 fn test_deserialize_decimal_scientific_length_boundary(
1762 #[case] zeros: usize,
1763 #[case] length: usize,
1764 #[case] scale: u32,
1765 ) {
1766 let value = format!("1.5{}e1", "0".repeat(zeros));
1767 let json = serde_json::to_string(&json!({"value": value})).unwrap();
1768 let required: TestDecimalOnly = serde_json::from_str(&json).unwrap();
1769 let optional: TestOptionalDecimalOnly = serde_json::from_str(&json).unwrap();
1770
1771 assert_eq!(value.len(), length);
1772 assert_eq!(required.value, dec!(15));
1773 assert_eq!(required.value.scale(), scale);
1774 assert_eq!(optional.value, Some(dec!(15)));
1775 assert_eq!(optional.value.unwrap().scale(), scale);
1776 }
1777
1778 #[rstest]
1779 #[case(".1e-2147483648")]
1780 #[case("-.1E-2147483648")]
1781 #[case("+.1e-2147483648")]
1782 fn test_deserialize_decimal_rejects_min_exponent(
1783 #[case] value: &str,
1784 #[values("visitor", "token", "token_borrowed")] route: &str,
1785 #[values(false, true)] optional: bool,
1786 ) {
1787 let json = serde_json::to_string(value).unwrap();
1788 let mut deserializer = serde_json::Deserializer::from_str(&json);
1789 let result = match (route, optional) {
1790 ("visitor", false) => deserialize_decimal(&mut deserializer).map(Some),
1791 ("visitor", true) => deserialize_optional_decimal(&mut deserializer),
1792 ("token", false) => deserialize_decimal_token(&mut deserializer).map(Some),
1793 ("token", true) => deserialize_optional_decimal_token(&mut deserializer),
1794 ("token_borrowed", false) => {
1795 deserialize_decimal_token_borrowed(&mut deserializer).map(Some)
1796 }
1797 ("token_borrowed", true) => {
1798 deserialize_optional_decimal_token_borrowed(&mut deserializer)
1799 }
1800 _ => unreachable!(),
1801 };
1802
1803 let error = result.unwrap_err();
1804 let expected = "Scale exceeds the maximum precision allowed: 2147483648 > 28";
1805
1806 assert_eq!(error.classify(), serde_json::error::Category::Data);
1807 assert_eq!(error.to_string().split(" at line ").next(), Some(expected));
1808 }
1809
1810 #[rstest]
1811 #[case(r#"{"value": "1.5e-8"}"#, dec!(0.000000015))]
1812 #[case(r#"{"value": "1E10"}"#, dec!(10000000000))]
1813 #[case(r#"{"value": "-1.23e5"}"#, dec!(-123000))]
1814 fn test_deserialize_decimal_scientific_string(#[case] json: &str, #[case] expected: Decimal) {
1815 let result: TestDecimalOnly = serde_json::from_str(json).unwrap();
1816 assert_eq!(result.value, expected);
1817 }
1818
1819 #[rstest]
1820 #[case(r#"{"value": 9223372036854775807}"#, dec!(9223372036854775807))] #[case(r#"{"value": -9223372036854775808}"#, dec!(-9223372036854775808))] #[case(r#"{"value": 0}"#, Decimal::ZERO)]
1823 fn test_deserialize_decimal_large_integers(#[case] json: &str, #[case] expected: Decimal) {
1824 let result: TestDecimalOnly = serde_json::from_str(json).unwrap();
1825 assert_eq!(result.value, expected);
1826 }
1827
1828 #[rstest]
1829 #[case(r#"{"value": "-123.456789"}"#, dec!(-123.456789))]
1830 #[case(r#"{"value": -999.99}"#, dec!(-999.99))]
1831 fn test_deserialize_decimal_negative(#[case] json: &str, #[case] expected: Decimal) {
1832 let result: TestDecimalOnly = serde_json::from_str(json).unwrap();
1833 assert_eq!(result.value, expected);
1834 }
1835
1836 #[rstest]
1837 #[case(r#"{"value": "123456789.123456789012345678"}"#)] fn test_deserialize_decimal_high_precision(#[case] json: &str) {
1839 let result: TestDecimalOnly = serde_json::from_str(json).unwrap();
1840 assert_eq!(result.value, dec!(123456789.123456789012345678));
1841 }
1842
1843 #[rstest]
1844 #[case(
1845 r#"{"value": "1.234567890123456789012345678912345e-1"}"#,
1846 "0.1234567890123456789012345679"
1847 )]
1848 #[case(
1849 r#"{"value": "0.1234567890123456789012345678912345"}"#,
1850 "0.1234567890123456789012345679"
1851 )]
1852 #[case(
1853 r#"{"value": "999999999999999999999999999995e-29"}"#,
1854 "10.000000000000000000000000000"
1855 )]
1856 #[case(r#"{"value": "0.5e29"}"#, "50000000000000000000000000000")]
1857 #[case(r#"{"value": "-4e-29"}"#, "0.0000000000000000000000000000")]
1858 #[case(r#"{"value": "1.5e-999999"}"#, "0.0000000000000000000000000000")]
1859 #[case(r#"{"value": "9e-999999"}"#, "0.0000000000000000000000000000")]
1860 #[case(r#"{"value": "0e2000000000"}"#, "0")]
1861 fn test_deserialize_decimal_rounds_high_scale_values(
1862 #[case] json: &str,
1863 #[case] expected: &str,
1864 ) {
1865 let result: TestDecimalOnly = serde_json::from_str(json).unwrap();
1867 assert_eq!(result.value.to_string(), expected);
1868 }
1869
1870 #[rstest]
1871 #[rstest]
1872 fn test_deserialize_decimal_negative_rounding_to_zero_loses_sign() {
1873 let json = r#"{"value": "-1.5e-999999"}"#;
1874 let result: TestDecimalOnly = serde_json::from_str(json).unwrap();
1875 assert_eq!(result.value.to_string(), "0.0000000000000000000000000000");
1876 }
1877
1878 #[rstest]
1879 #[case(r#"{"value": "899999999999999999999999999995e-29"}"#)]
1880 #[case(r#"{"value": "+899999999999999999999999999995e-29"}"#)]
1881 fn test_deserialize_decimal_rounding_carries_into_integer(#[case] json: &str) {
1882 let result: TestDecimalOnly = serde_json::from_str(json).unwrap();
1884 assert_eq!(result.value.to_string(), "9.000000000000000000000000000");
1885 }
1886
1887 #[rstest]
1888 #[case(r#"{"value": "8e28"}"#)] #[case(r#"{"value": "1e1000000000"}"#)] #[case(r#"{"value": {"number": "1.5"}}"#)]
1891 #[case(r#"{"value": "not-a-number"}"#)]
1892 #[case(r#"{"value": "1.2.3e1"}"#)] #[case(r#"{"value": ".e1"}"#)] fn test_deserialize_decimal_rejects_unrepresentable_values(#[case] json: &str) {
1895 let result: Result<TestDecimalOnly, _> = serde_json::from_str(json);
1898 assert!(result.is_err());
1899 }
1900
1901 #[rstest]
1902 fn test_deserialize_optional_decimal_rounds_high_scale_values() {
1903 let json = r#"{"value": "51.234567890123456789012345678912345e-1"}"#;
1904 let result: TestOptionalDecimalOnly = serde_json::from_str(json).unwrap();
1905 assert_eq!(
1906 result.value.map(|v| v.to_string()),
1907 Some("5.1234567890123456789012345679".into()),
1908 );
1909 }
1910
1911 #[derive(Debug, Deserialize)]
1912 struct TestOptionalDecimalOnly {
1913 #[serde(deserialize_with = "deserialize_optional_decimal")]
1914 value: Option<Decimal>,
1915 }
1916
1917 #[rstest]
1918 #[case(r#"{"value": "1.5e-8"}"#, Some(dec!(0.000000015)))]
1919 #[case(r#"{"value": null}"#, None)]
1920 #[case(r#"{"value": ""}"#, None)]
1921 #[case(r#"{"value": 42}"#, Some(dec!(42)))]
1922 #[case(r#"{"value": -100.5}"#, Some(dec!(-100.5)))]
1923 fn test_deserialize_optional_decimal_various(
1924 #[case] json: &str,
1925 #[case] expected: Option<Decimal>,
1926 ) {
1927 let result: TestOptionalDecimalOnly = serde_json::from_str(json).unwrap();
1928 assert_eq!(result.value, expected);
1929 }
1930
1931 #[rstest]
1932 fn test_decimal_visitor_direct_owned_and_wide_integer_paths() {
1933 assert_eq!(
1934 DecimalVisitor
1935 .visit_string::<ValueError>("1.5".to_string())
1936 .unwrap(),
1937 dec!(1.5)
1938 );
1939 assert_eq!(
1940 DecimalVisitor.visit_i128::<ValueError>(5).unwrap(),
1941 Decimal::from(5i128)
1942 );
1943 assert_eq!(
1944 DecimalVisitor.visit_u128::<ValueError>(5).unwrap(),
1945 Decimal::from(5u128)
1946 );
1947 assert_eq!(
1948 DecimalVisitor.visit_none::<ValueError>().unwrap(),
1949 Decimal::ZERO
1950 );
1951 }
1952
1953 #[rstest]
1954 fn test_decimal_visitor_rejects_non_finite_float() {
1955 assert!(
1956 DecimalVisitor
1957 .visit_f64::<ValueError>(f64::INFINITY)
1958 .is_err()
1959 );
1960 assert!(
1961 DecimalVisitor
1962 .visit_f64::<ValueError>(f64::NEG_INFINITY)
1963 .is_err()
1964 );
1965 assert!(DecimalVisitor.visit_f64::<ValueError>(f64::NAN).is_err());
1966 }
1967
1968 #[rstest]
1969 fn test_optional_decimal_visitor_direct_paths() {
1970 assert_eq!(
1971 OptionalDecimalVisitor
1972 .visit_string::<ValueError>("1.5".to_string())
1973 .unwrap(),
1974 Some(dec!(1.5))
1975 );
1976 assert_eq!(
1977 OptionalDecimalVisitor.visit_i64::<ValueError>(42).unwrap(),
1978 Some(dec!(42))
1979 );
1980 assert_eq!(
1981 OptionalDecimalVisitor.visit_i128::<ValueError>(5).unwrap(),
1982 Some(Decimal::from(5i128))
1983 );
1984 assert_eq!(
1985 OptionalDecimalVisitor.visit_u128::<ValueError>(5).unwrap(),
1986 Some(Decimal::from(5u128))
1987 );
1988 assert_eq!(
1989 OptionalDecimalVisitor.visit_none::<ValueError>().unwrap(),
1990 None
1991 );
1992 }
1993
1994 #[rstest]
1995 fn test_serialize_optional_decimal_none_serializes_null() {
1996 let original = TestFlexibleDecimal {
1997 value: dec!(1),
1998 optional_value: None,
1999 };
2000
2001 let json = serde_json::to_string(&original).unwrap();
2002 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
2003 assert_eq!(parsed["optional_value"], json!(null));
2004 }
2005
2006 #[rstest]
2007 fn test_serde_bool_defaults() {
2008 assert!(default_true());
2009 assert!(!default_false());
2010 }
2011
2012 use proptest::prelude::*;
2013 use rust_decimal::prelude::ToPrimitive;
2014
2015 fn representable_decimal_strategy() -> impl Strategy<Value = Decimal> {
2016 (
2019 -79_228_162_514_264_337_593_543_950_335i128
2020 ..=79_228_162_514_264_337_593_543_950_335i128,
2021 0u32..=28u32,
2022 )
2023 .prop_map(|(mantissa, scale)| Decimal::from_i128_with_scale(mantissa, scale))
2024 }
2025
2026 fn numeric_string_strategy() -> impl Strategy<Value = String> {
2027 (
2030 proptest::bool::ANY,
2031 "[0-9]{1,30}",
2032 proptest::option::of("[0-9]{1,40}"),
2033 proptest::option::of(-40i32..=40),
2034 )
2035 .prop_map(|(negative, integer, fraction, exponent)| {
2036 let mut value = String::new();
2037 if negative {
2038 value.push('-');
2039 }
2040 value.push_str(&integer);
2041 if let Some(fraction) = fraction {
2042 value.push('.');
2043 value.push_str(&fraction);
2044 }
2045
2046 if let Some(exponent) = exponent {
2047 value.push('e');
2048 value.push_str(&exponent.to_string());
2049 }
2050 value
2051 })
2052 }
2053
2054 proptest! {
2055 #[rstest]
2056 fn prop_deserialize_decimal_scientific_roundtrips_representable_values(
2057 expected in representable_decimal_strategy(),
2058 zeros in 0usize..=35,
2059 ) {
2060 let scientific = format!(
2061 "{}{}e-{}",
2062 expected.mantissa(),
2063 "0".repeat(zeros),
2064 expected.scale() as usize + zeros,
2065 );
2066 let json = serde_json::to_string(&json!({"value": scientific})).unwrap();
2067 let required: TestDecimalOnly = serde_json::from_str(&json).unwrap();
2068 let optional: TestOptionalDecimalOnly = serde_json::from_str(&json).unwrap();
2069
2070 prop_assert_eq!(required.value, expected);
2071 prop_assert_eq!(optional.value, Some(expected));
2072 }
2073
2074 #[rstest]
2075 fn prop_deserialize_decimal_roundtrips_representable_values(
2076 expected in representable_decimal_strategy()
2077 ) {
2078 let json = format!(r#"{{"value": "{expected}"}}"#);
2081 let parsed: TestDecimalOnly = serde_json::from_str(&json).unwrap();
2082 prop_assert_eq!(parsed.value, expected);
2083 }
2084
2085 #[rstest]
2086 fn prop_deserialize_decimal_total_on_arbitrary_strings(value in "\\PC{0,64}") {
2087 let json = serde_json::to_string(&serde_json::json!({"value": value})).unwrap();
2089 let _ = serde_json::from_str::<TestDecimalOnly>(&json);
2090 }
2091
2092 #[rstest]
2093 fn prop_deserialize_decimal_tracks_f64_reference(value in numeric_string_strategy()) {
2094 let json = format!(r#"{{"value": "{value}"}}"#);
2097 if let Ok(parsed) = serde_json::from_str::<TestDecimalOnly>(&json) {
2098 let reference: f64 = value.parse().unwrap();
2099 let decoded = parsed.value.to_f64().unwrap();
2100 prop_assert!(
2101 (decoded - reference).abs() <= reference.abs() * 1e-9 + 1e-27,
2102 "decoded {decoded} diverges from reference {reference} for input {value}",
2103 );
2104 }
2105 }
2106
2107 #[rstest]
2108 fn prop_deserialize_optional_decimal_matches_required(
2109 value in numeric_string_strategy()
2110 ) {
2111 let json = format!(r#"{{"value": "{value}"}}"#);
2112 let required = serde_json::from_str::<TestDecimalOnly>(&json);
2113 let optional = serde_json::from_str::<TestOptionalDecimalOnly>(&json);
2114 match (required, optional) {
2115 (Ok(required), Ok(optional)) => {
2116 prop_assert_eq!(optional.value, Some(required.value));
2117 }
2118 (Err(_), Err(_)) => {}
2119 (required, optional) => prop_assert!(
2120 false,
2121 "required and optional decoding disagree for input {}: {:?} vs {:?}",
2122 value,
2123 required.map(|r| r.value),
2124 optional.map(|o| o.value),
2125 ),
2126 }
2127 }
2128 }
2129
2130 #[derive(Debug, Deserialize)]
2131 struct Token(#[serde(deserialize_with = "deserialize_decimal_token_borrowed")] Decimal);
2132
2133 #[rstest]
2134 #[case(r#""1.2300""#, 12300, 4)]
2135 #[case(r#""\u0031.2300""#, 12300, 4)]
2136 #[case(r#""1.2300\u0030""#, 123_000, 5)]
2137 #[case(r#""-0.00001000""#, -1000, 8)]
2138 #[case("9007199254740993", 9_007_199_254_740_993, 0)]
2139 #[case("18446744073709551617", 18_446_744_073_709_551_617, 0)]
2140 fn test_decimal_token_preserves_digits_and_scale(
2141 #[case] json: &str,
2142 #[case] mantissa: i128,
2143 #[case] scale: u32,
2144 ) {
2145 let value = serde_json::from_str::<Token>(json).unwrap().0;
2146 assert_eq!(value.mantissa(), mantissa);
2147 assert_eq!(value.scale(), scale);
2148 }
2149
2150 #[rstest]
2151 #[case(r#""\uD800""#)]
2152 #[case(r#""\uDC00""#)]
2153 #[case(r#""\q""#)]
2154 #[case(r#""1.2\n3""#)]
2155 #[case(r#""1.2\"3""#)]
2156 fn test_decimal_token_rejects_invalid_strings(#[case] json: &str) {
2157 assert!(serde_json::from_str::<Token>(json).is_err());
2158 }
2159}