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