1use core::marker::PhantomData;
30
31use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
32
33#[cfg(feature = "alloc")]
34use alloc::string::ToString;
35
36use crate::core_type::I128;
37
38impl<const SCALE: u32> Serialize for I128<SCALE> {
41 #[inline]
48 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
49 if serializer.is_human_readable() {
50 #[cfg(feature = "alloc")]
54 {
55 serializer.serialize_str(&self.0.to_string())
56 }
57 #[cfg(not(feature = "alloc"))]
62 {
63 let _ = serializer;
64 Err(serde::ser::Error::custom(
65 "decimal-scaled: human-readable serialisation requires the `alloc` feature",
66 ))
67 }
68 } else {
69 serializer.serialize_bytes(&self.0.to_le_bytes())
71 }
72 }
73}
74
75impl<'de, const SCALE: u32> Deserialize<'de> for I128<SCALE> {
78 #[inline]
91 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
92 let visitor = decimal_serde::DecimalVisitor::<SCALE>(PhantomData);
93 if deserializer.is_human_readable() {
94 deserializer.deserialize_any(visitor)
95 } else {
96 deserializer.deserialize_bytes(visitor)
97 }
98 }
99}
100
101pub mod decimal_serde {
123 use super::*;
124
125 #[inline]
134 pub fn serialize<const SCALE: u32, S: Serializer>(
135 v: &I128<SCALE>,
136 s: S,
137 ) -> Result<S::Ok, S::Error> {
138 v.serialize(s)
139 }
140
141 #[inline]
150 pub fn deserialize<'de, const SCALE: u32, D: Deserializer<'de>>(
151 d: D,
152 ) -> Result<I128<SCALE>, D::Error> {
153 I128::<SCALE>::deserialize(d)
154 }
155
156 pub struct DecimalVisitor<const SCALE: u32>(pub PhantomData<()>);
170
171 impl<'de, const SCALE: u32> Visitor<'de> for DecimalVisitor<SCALE> {
172 type Value = I128<SCALE>;
173
174 fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
175 f.write_str(
176 "a base-10 i128 integer string, 16 little-endian bytes, \
177 or a native integer",
178 )
179 }
180
181 fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
184 let bytes = v.as_bytes();
194 if bytes.is_empty() {
195 return Err(serde::de::Error::custom(
196 "decimal-scaled: empty string is not a valid i128 wire",
197 ));
198 }
199 if bytes[0] == b'+' {
200 return Err(serde::de::Error::custom(
201 "decimal-scaled: leading `+` is not part of the canonical wire format",
202 ));
203 }
204 v.parse::<i128>()
205 .map(I128::<SCALE>::from_bits)
206 .map_err(|_| {
207 serde::de::Error::custom(
208 "decimal-scaled: expected a base-10 i128 integer string",
209 )
210 })
211 }
212
213 fn visit_borrowed_str<E: serde::de::Error>(self, v: &'de str) -> Result<Self::Value, E> {
214 self.visit_str(v)
215 }
216
217 #[cfg(feature = "alloc")]
218 fn visit_string<E: serde::de::Error>(
219 self,
220 v: alloc::string::String,
221 ) -> Result<Self::Value, E> {
222 self.visit_str(&v)
223 }
224
225 fn visit_bytes<E: serde::de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
228 let arr: [u8; 16] = v.try_into().map_err(|_| {
230 serde::de::Error::invalid_length(
231 v.len(),
232 &"exactly 16 little-endian bytes for an i128",
233 )
234 })?;
235 Ok(I128::<SCALE>::from_bits(i128::from_le_bytes(arr)))
236 }
237
238 fn visit_borrowed_bytes<E: serde::de::Error>(
239 self,
240 v: &'de [u8],
241 ) -> Result<Self::Value, E> {
242 self.visit_bytes(v)
243 }
244
245 #[cfg(feature = "alloc")]
246 fn visit_byte_buf<E: serde::de::Error>(
247 self,
248 v: alloc::vec::Vec<u8>,
249 ) -> Result<Self::Value, E> {
250 self.visit_bytes(&v)
251 }
252
253 fn visit_i8<E: serde::de::Error>(self, v: i8) -> Result<Self::Value, E> {
262 Ok(I128::<SCALE>::from_bits(v as i128))
263 }
264
265 fn visit_i16<E: serde::de::Error>(self, v: i16) -> Result<Self::Value, E> {
266 Ok(I128::<SCALE>::from_bits(v as i128))
267 }
268
269 fn visit_i32<E: serde::de::Error>(self, v: i32) -> Result<Self::Value, E> {
270 Ok(I128::<SCALE>::from_bits(v as i128))
271 }
272
273 fn visit_i64<E: serde::de::Error>(self, v: i64) -> Result<Self::Value, E> {
274 Ok(I128::<SCALE>::from_bits(v as i128))
275 }
276
277 fn visit_i128<E: serde::de::Error>(self, v: i128) -> Result<Self::Value, E> {
278 Ok(I128::<SCALE>::from_bits(v))
279 }
280
281 fn visit_u8<E: serde::de::Error>(self, v: u8) -> Result<Self::Value, E> {
282 Ok(I128::<SCALE>::from_bits(v as i128))
283 }
284
285 fn visit_u16<E: serde::de::Error>(self, v: u16) -> Result<Self::Value, E> {
286 Ok(I128::<SCALE>::from_bits(v as i128))
287 }
288
289 fn visit_u32<E: serde::de::Error>(self, v: u32) -> Result<Self::Value, E> {
290 Ok(I128::<SCALE>::from_bits(v as i128))
291 }
292
293 fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<Self::Value, E> {
294 Ok(I128::<SCALE>::from_bits(v as i128))
295 }
296
297 fn visit_u128<E: serde::de::Error>(self, v: u128) -> Result<Self::Value, E> {
298 i128::try_from(v).map(I128::<SCALE>::from_bits).map_err(|_| {
301 serde::de::Error::custom(
302 "decimal-scaled: u128 value exceeds i128 storage range",
303 )
304 })
305 }
306
307 }
316}
317
318#[cfg(all(test, feature = "alloc", feature = "serde"))]
321mod tests {
322 use super::*;
323 use crate::core_type::{I128, I128s12};
324 use serde::de::value::{Error as DeError, StrDeserializer};
325 use serde::de::IntoDeserializer;
326 use alloc::format;
327
328 #[test]
332 fn deserialize_canonical_zero_string() {
333 let de: StrDeserializer<DeError> = "0".into_deserializer();
334 let v: I128s12 = I128s12::deserialize(de).unwrap();
335 assert_eq!(v, I128s12::ZERO);
336 }
337
338 #[test]
341 fn visitor_accepts_scaled_one_str() {
342 let visitor = decimal_serde::DecimalVisitor::<12>(PhantomData);
343 let v: I128s12 =
344 <_ as Visitor>::visit_str::<DeError>(visitor, "1000000000000").unwrap();
345 assert_eq!(v, I128s12::ONE);
346 }
347
348 #[test]
351 fn visitor_rejects_decimal_point_str() {
352 let visitor = decimal_serde::DecimalVisitor::<12>(PhantomData);
353 let res: Result<I128s12, _> =
354 <_ as Visitor>::visit_str::<DeError>(visitor, "1.5");
355 assert!(res.is_err(), "expected reject; got Ok({:?})", res);
356 }
357
358 #[test]
363 fn visitor_accepts_i64_as_storage() {
364 let visitor = decimal_serde::DecimalVisitor::<12>(PhantomData);
365 let v: I128s12 = <_ as Visitor>::visit_i64::<DeError>(visitor, -5).unwrap();
366 assert_eq!(v.to_bits(), -5);
367 }
368
369 #[test]
371 fn visitor_accepts_u64_max() {
372 let visitor = decimal_serde::DecimalVisitor::<12>(PhantomData);
373 let v: I128s12 =
374 <_ as Visitor>::visit_u64::<DeError>(visitor, u64::MAX).unwrap();
375 assert_eq!(v.to_bits(), u64::MAX as i128);
376 }
377
378 #[test]
381 fn visitor_rejects_u128_above_i128_max() {
382 let visitor = decimal_serde::DecimalVisitor::<12>(PhantomData);
383 let res: Result<I128s12, _> = <_ as Visitor>::visit_u128::<DeError>(
384 visitor,
385 (i128::MAX as u128) + 1,
386 );
387 assert!(res.is_err(), "expected overflow reject; got Ok({:?})", res);
388 }
389
390 #[test]
396 fn json_one_serialises_as_scaled_integer_string() {
397 let json = serde_json::to_string(&I128s12::ONE).unwrap();
398 assert_eq!(json, "\"1000000000000\"");
399 }
400
401 #[test]
402 fn json_zero_serialises_as_zero_string() {
403 let json = serde_json::to_string(&I128s12::ZERO).unwrap();
404 assert_eq!(json, "\"0\"");
405 }
406
407 #[test]
408 fn json_one_round_trips() {
409 let json = serde_json::to_string(&I128s12::ONE).unwrap();
410 let back: I128s12 = serde_json::from_str(&json).unwrap();
411 assert_eq!(back, I128s12::ONE);
412 }
413
414 #[test]
415 fn json_zero_round_trips() {
416 let json = serde_json::to_string(&I128s12::ZERO).unwrap();
417 let back: I128s12 = serde_json::from_str(&json).unwrap();
418 assert_eq!(back, I128s12::ZERO);
419 }
420
421 #[test]
424 fn json_negative_round_trips() {
425 let v = I128s12::from(-5_i32);
426 let json = serde_json::to_string(&v).unwrap();
427 assert_eq!(json, "\"-5000000000000\"");
428 let back: I128s12 = serde_json::from_str(&json).unwrap();
429 assert_eq!(back, v);
430 assert_eq!(back.to_bits(), -5_000_000_000_000_i128);
431 }
432
433 #[test]
436 fn json_max_round_trips() {
437 let json = serde_json::to_string(&I128s12::MAX).unwrap();
438 let back: I128s12 = serde_json::from_str(&json).unwrap();
439 assert_eq!(back, I128s12::MAX);
440 }
441
442 #[test]
443 fn json_min_round_trips() {
444 let json = serde_json::to_string(&I128s12::MIN).unwrap();
445 let back: I128s12 = serde_json::from_str(&json).unwrap();
446 assert_eq!(back, I128s12::MIN);
447 }
448
449 #[test]
453 fn json_string_matches_i128_to_string() {
454 let raw: i128 = -123_456_789_012_345_678_901_234_567_890_i128;
455 let v = I128s12::from_bits(raw);
456 let json = serde_json::to_string(&v).unwrap();
457 assert_eq!(json, format!("\"{}\"", raw));
458 }
459
460 #[test]
463 fn json_rejects_decimal_point_string() {
464 let res: Result<I128s12, _> = serde_json::from_str("\"1.5\"");
465 assert!(res.is_err(), "expected reject; got Ok({:?})", res);
466 }
467
468 #[test]
469 fn json_rejects_scientific_notation_string() {
470 let res: Result<I128s12, _> = serde_json::from_str("\"1e6\"");
471 assert!(res.is_err(), "expected reject; got Ok({:?})", res);
472 }
473
474 #[test]
475 fn json_rejects_not_a_number_string() {
476 let res: Result<I128s12, _> = serde_json::from_str("\"not-a-number\"");
477 assert!(res.is_err(), "expected reject; got Ok({:?})", res);
478 }
479
480 #[test]
481 fn json_rejects_empty_string() {
482 let res: Result<I128s12, _> = serde_json::from_str("\"\"");
483 assert!(res.is_err(), "expected reject; got Ok({:?})", res);
484 }
485
486 #[test]
487 fn json_rejects_leading_whitespace_string() {
488 let res: Result<I128s12, _> = serde_json::from_str("\" 42\"");
491 assert!(res.is_err(), "expected reject; got Ok({:?})", res);
492 }
493
494 #[test]
495 fn json_rejects_plus_prefix() {
496 let res: Result<I128s12, _> = serde_json::from_str("\"+42\"");
497 assert!(res.is_err(), "expected reject; got Ok({:?})", res);
498 }
499
500 #[test]
503 fn json_accepts_bare_integer_number_as_storage() {
504 let back: I128s12 = serde_json::from_str("42").unwrap();
505 assert_eq!(back.to_bits(), 42_i128);
506 }
507
508 #[test]
511 fn postcard_one_round_trips() {
512 let bytes: alloc::vec::Vec<u8> = postcard::to_allocvec(&I128s12::ONE).unwrap();
513 let raw = I128s12::ONE.to_bits().to_le_bytes();
516 assert!(bytes.windows(16).any(|w| w == raw));
517 let back: I128s12 = postcard::from_bytes(&bytes).unwrap();
518 assert_eq!(back, I128s12::ONE);
519 }
520
521 #[test]
522 fn postcard_zero_round_trips() {
523 let bytes: alloc::vec::Vec<u8> = postcard::to_allocvec(&I128s12::ZERO).unwrap();
524 let back: I128s12 = postcard::from_bytes(&bytes).unwrap();
525 assert_eq!(back, I128s12::ZERO);
526 }
527
528 #[test]
529 fn postcard_negative_round_trips() {
530 let v = I128s12::from(-5_i32);
531 let bytes: alloc::vec::Vec<u8> = postcard::to_allocvec(&v).unwrap();
532 let back: I128s12 = postcard::from_bytes(&bytes).unwrap();
533 assert_eq!(back, v);
534 }
535
536 #[test]
537 fn postcard_max_round_trips() {
538 let bytes: alloc::vec::Vec<u8> = postcard::to_allocvec(&I128s12::MAX).unwrap();
539 let back: I128s12 = postcard::from_bytes(&bytes).unwrap();
540 assert_eq!(back, I128s12::MAX);
541 }
542
543 #[test]
544 fn postcard_min_round_trips() {
545 let bytes: alloc::vec::Vec<u8> = postcard::to_allocvec(&I128s12::MIN).unwrap();
546 let back: I128s12 = postcard::from_bytes(&bytes).unwrap();
547 assert_eq!(back, I128s12::MIN);
548 }
549
550 #[test]
554 fn postcard_byte_order_matches_le() {
555 let v = I128s12::from_bits(0x0123_4567_89AB_CDEF_FEDC_BA98_7654_3210_i128);
556 let bytes: alloc::vec::Vec<u8> = postcard::to_allocvec(&v).unwrap();
557 let raw = v.to_bits().to_le_bytes();
558 let found = bytes.windows(16).position(|w| w == raw);
559 assert!(found.is_some(), "expected raw LE bytes embedded; got {:?}", bytes);
560 assert_eq!(raw[0], 0x10); assert_eq!(raw[15], 0x01); }
563
564 #[test]
569 fn cross_format_json_string_matches_le_bytes() {
570 let v = I128s12::from(42_i32);
571 let json = serde_json::to_string(&v).unwrap();
572 let inner = json.trim_matches('"');
573 let parsed: i128 = inner.parse().unwrap();
574 let json_bytes = parsed.to_le_bytes();
575 let direct_bytes = v.to_bits().to_le_bytes();
576 assert_eq!(json_bytes, direct_bytes);
577 }
578
579 #[test]
583 fn cross_scale_wire_is_storage_only() {
584 let raw: i128 = 1_500_000_000_000;
585 let v12 = I128::<12>::from_bits(raw);
586 let v6 = I128::<6>::from_bits(raw);
587 assert_eq!(serde_json::to_string(&v12).unwrap(), "\"1500000000000\"");
588 assert_eq!(serde_json::to_string(&v6).unwrap(), "\"1500000000000\"");
589 }
590
591 #[test]
596 fn decimal_serde_helper_round_trips() {
597 #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)]
598 struct Holder {
599 #[serde(with = "crate::serde_helpers::decimal_serde")]
600 length: I128<12>,
601 }
602
603 let h = Holder {
604 length: I128s12::from(7_i32),
605 };
606 let json = serde_json::to_string(&h).unwrap();
607 assert_eq!(json, r#"{"length":"7000000000000"}"#);
608 let back: Holder = serde_json::from_str(&json).unwrap();
609 assert_eq!(back, h);
610 }
611}