1pub(crate) const JS_MAX_SAFE_INTEGER: u64 = 9_007_199_254_740_991;
21
22pub mod json_safe_u64 {
24 use serde::de::{self, Deserializer, Visitor};
25 use serde::ser::Serializer;
26
27 use super::JS_MAX_SAFE_INTEGER;
28
29 pub fn serialize<S: Serializer>(value: &u64, serializer: S) -> Result<S::Ok, S::Error> {
30 if serializer.is_human_readable() && *value > JS_MAX_SAFE_INTEGER {
31 serializer.serialize_str(&value.to_string())
32 } else {
33 serializer.serialize_u64(*value)
34 }
35 }
36
37 pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<u64, D::Error> {
38 if deserializer.is_human_readable() {
39 deserializer.deserialize_any(U64OrStringVisitor)
40 } else {
41 serde::Deserialize::deserialize(deserializer)
42 }
43 }
44
45 struct U64OrStringVisitor;
46
47 impl<'de> Visitor<'de> for U64OrStringVisitor {
48 type Value = u64;
49
50 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
51 formatter.write_str("a u64 or a string containing a u64")
52 }
53
54 fn visit_u64<E: de::Error>(self, v: u64) -> Result<Self::Value, E> {
55 Ok(v)
56 }
57
58 fn visit_i64<E: de::Error>(self, v: i64) -> Result<Self::Value, E> {
59 u64::try_from(v)
60 .map_err(|_| de::Error::custom(format!("i64 value {v} out of u64 range")))
61 }
62
63 fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
64 v.parse::<u64>()
65 .map_err(|_| de::Error::custom(format!("invalid u64 string: {v}")))
66 }
67 }
68}
69
70pub mod json_safe_i64 {
72 use serde::de::{self, Deserializer, Visitor};
73 use serde::ser::Serializer;
74
75 use super::JS_MAX_SAFE_INTEGER;
76
77 const JS_MIN_SAFE_INTEGER: i64 = -(JS_MAX_SAFE_INTEGER as i64);
78
79 pub fn serialize<S: Serializer>(value: &i64, serializer: S) -> Result<S::Ok, S::Error> {
80 if serializer.is_human_readable()
81 && (*value > JS_MAX_SAFE_INTEGER as i64 || *value < JS_MIN_SAFE_INTEGER)
82 {
83 serializer.serialize_str(&value.to_string())
84 } else {
85 serializer.serialize_i64(*value)
86 }
87 }
88
89 pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<i64, D::Error> {
90 if deserializer.is_human_readable() {
91 deserializer.deserialize_any(I64OrStringVisitor)
92 } else {
93 serde::Deserialize::deserialize(deserializer)
94 }
95 }
96
97 struct I64OrStringVisitor;
98
99 impl<'de> Visitor<'de> for I64OrStringVisitor {
100 type Value = i64;
101
102 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
103 formatter.write_str("an i64 or a string containing an i64")
104 }
105
106 fn visit_i64<E: de::Error>(self, v: i64) -> Result<Self::Value, E> {
107 Ok(v)
108 }
109
110 fn visit_u64<E: de::Error>(self, v: u64) -> Result<Self::Value, E> {
111 i64::try_from(v)
112 .map_err(|_| de::Error::custom(format!("u64 value {v} out of i64 range")))
113 }
114
115 fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
116 v.parse::<i64>()
117 .map_err(|_| de::Error::custom(format!("invalid i64 string: {v}")))
118 }
119 }
120}
121
122pub mod json_safe_option_u64 {
124 use serde::de::{self, Deserializer, Visitor};
125 use serde::ser::Serializer;
126
127 pub fn serialize<S: Serializer>(value: &Option<u64>, serializer: S) -> Result<S::Ok, S::Error> {
128 match value {
129 Some(v) => super::json_safe_u64::serialize(v, serializer),
130 None => serializer.serialize_none(),
131 }
132 }
133
134 pub fn deserialize<'de, D: Deserializer<'de>>(
135 deserializer: D,
136 ) -> Result<Option<u64>, D::Error> {
137 if deserializer.is_human_readable() {
138 deserializer.deserialize_option(OptionU64Visitor)
139 } else {
140 serde::Deserialize::deserialize(deserializer)
141 }
142 }
143
144 struct OptionU64Visitor;
145
146 impl<'de> Visitor<'de> for OptionU64Visitor {
147 type Value = Option<u64>;
148
149 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
150 formatter.write_str("null, a u64, or a string containing a u64")
151 }
152
153 fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
154 Ok(None)
155 }
156
157 fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
158 Ok(None)
159 }
160
161 fn visit_some<D: Deserializer<'de>>(
162 self,
163 deserializer: D,
164 ) -> Result<Self::Value, D::Error> {
165 super::json_safe_u64::deserialize(deserializer).map(Some)
166 }
167 }
168}
169
170pub mod json_safe_option_i64 {
172 use serde::de::{self, Deserializer, Visitor};
173 use serde::ser::Serializer;
174
175 pub fn serialize<S: Serializer>(value: &Option<i64>, serializer: S) -> Result<S::Ok, S::Error> {
176 match value {
177 Some(v) => super::json_safe_i64::serialize(v, serializer),
178 None => serializer.serialize_none(),
179 }
180 }
181
182 pub fn deserialize<'de, D: Deserializer<'de>>(
183 deserializer: D,
184 ) -> Result<Option<i64>, D::Error> {
185 if deserializer.is_human_readable() {
186 deserializer.deserialize_option(OptionI64Visitor)
187 } else {
188 serde::Deserialize::deserialize(deserializer)
189 }
190 }
191
192 struct OptionI64Visitor;
193
194 impl<'de> Visitor<'de> for OptionI64Visitor {
195 type Value = Option<i64>;
196
197 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
198 formatter.write_str("null, an i64, or a string containing an i64")
199 }
200
201 fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
202 Ok(None)
203 }
204
205 fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
206 Ok(None)
207 }
208
209 fn visit_some<D: Deserializer<'de>>(
210 self,
211 deserializer: D,
212 ) -> Result<Self::Value, D::Error> {
213 super::json_safe_i64::deserialize(deserializer).map(Some)
214 }
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221 use serde::{Deserialize, Serialize};
222
223 #[derive(Debug, PartialEq, Serialize, Deserialize)]
224 struct TestU64 {
225 #[serde(with = "json_safe_u64")]
226 value: u64,
227 }
228
229 #[derive(Debug, PartialEq, Serialize, Deserialize)]
230 struct TestI64 {
231 #[serde(with = "json_safe_i64")]
232 value: i64,
233 }
234
235 #[derive(Debug, PartialEq, Serialize, Deserialize)]
236 struct TestOptionU64 {
237 #[serde(default, with = "json_safe_option_u64")]
238 value: Option<u64>,
239 }
240
241 #[derive(Debug, PartialEq, Serialize, Deserialize)]
242 struct TestOptionI64 {
243 #[serde(default, with = "json_safe_option_i64")]
244 value: Option<i64>,
245 }
246
247 #[test]
248 fn u64_small_value_stays_number() {
249 let t = TestU64 { value: 42 };
250 let json = serde_json::to_value(&t).unwrap();
251 assert!(json["value"].is_number());
252 assert_eq!(json["value"].as_u64().unwrap(), 42);
253
254 let restored: TestU64 = serde_json::from_value(json).unwrap();
255 assert_eq!(t, restored);
256 }
257
258 #[test]
259 fn u64_large_value_becomes_string() {
260 let t = TestU64 { value: u64::MAX };
261 let json = serde_json::to_value(&t).unwrap();
262 assert!(json["value"].is_string());
263 assert_eq!(json["value"].as_str().unwrap(), "18446744073709551615");
264
265 let restored: TestU64 = serde_json::from_value(json).unwrap();
266 assert_eq!(t, restored);
267 }
268
269 #[test]
270 fn u64_at_max_safe_integer_stays_number() {
271 let t = TestU64 {
272 value: JS_MAX_SAFE_INTEGER,
273 };
274 let json = serde_json::to_value(&t).unwrap();
275 assert!(json["value"].is_number());
276 }
277
278 #[test]
279 fn u64_above_max_safe_integer_becomes_string() {
280 let t = TestU64 {
281 value: JS_MAX_SAFE_INTEGER + 1,
282 };
283 let json = serde_json::to_value(&t).unwrap();
284 assert!(json["value"].is_string());
285 }
286
287 #[test]
288 fn i64_small_value_stays_number() {
289 let t = TestI64 { value: -42 };
290 let json = serde_json::to_value(&t).unwrap();
291 assert!(json["value"].is_number());
292
293 let restored: TestI64 = serde_json::from_value(json).unwrap();
294 assert_eq!(t, restored);
295 }
296
297 #[test]
298 fn i64_large_value_becomes_string() {
299 let t = TestI64 { value: i64::MAX };
300 let json = serde_json::to_value(&t).unwrap();
301 assert!(json["value"].is_string());
302
303 let restored: TestI64 = serde_json::from_value(json).unwrap();
304 assert_eq!(t, restored);
305 }
306
307 #[test]
308 fn i64_large_negative_becomes_string() {
309 let t = TestI64 { value: i64::MIN };
310 let json = serde_json::to_value(&t).unwrap();
311 assert!(json["value"].is_string());
312
313 let restored: TestI64 = serde_json::from_value(json).unwrap();
314 assert_eq!(t, restored);
315 }
316
317 #[test]
318 fn option_u64_none_round_trip() {
319 let t = TestOptionU64 { value: None };
320 let json = serde_json::to_value(&t).unwrap();
321 assert!(json["value"].is_null());
322
323 let restored: TestOptionU64 = serde_json::from_value(json).unwrap();
324 assert_eq!(t, restored);
325 }
326
327 #[test]
328 fn option_u64_large_round_trip() {
329 let t = TestOptionU64 {
330 value: Some(u64::MAX),
331 };
332 let json = serde_json::to_value(&t).unwrap();
333 assert!(json["value"].is_string());
334
335 let restored: TestOptionU64 = serde_json::from_value(json).unwrap();
336 assert_eq!(t, restored);
337 }
338
339 #[test]
340 fn platform_value_u64_stays_native() {
341 let t = TestU64 { value: u64::MAX };
342 let pv = platform_value::to_value(&t).unwrap();
343
344 let restored: TestU64 = platform_value::from_value(pv).unwrap();
346 assert_eq!(t, restored);
347 }
348
349 #[test]
350 fn option_i64_none_round_trip() {
351 let t = TestOptionI64 { value: None };
352 let json = serde_json::to_value(&t).unwrap();
353 assert!(json["value"].is_null());
354
355 let restored: TestOptionI64 = serde_json::from_value(json).unwrap();
356 assert_eq!(t, restored);
357 }
358
359 #[test]
360 fn option_i64_large_round_trip() {
361 let t = TestOptionI64 {
362 value: Some(i64::MAX),
363 };
364 let json = serde_json::to_value(&t).unwrap();
365 assert!(json["value"].is_string());
366
367 let restored: TestOptionI64 = serde_json::from_value(json).unwrap();
368 assert_eq!(t, restored);
369 }
370
371 #[test]
372 fn option_i64_large_negative_round_trip() {
373 let t = TestOptionI64 {
374 value: Some(i64::MIN),
375 };
376 let json = serde_json::to_value(&t).unwrap();
377 assert!(json["value"].is_string());
378
379 let restored: TestOptionI64 = serde_json::from_value(json).unwrap();
380 assert_eq!(t, restored);
381 }
382
383 #[test]
384 fn option_i64_missing_field_deserializes_as_none() {
385 let json = serde_json::json!({});
386 let restored: TestOptionI64 = serde_json::from_value(json).unwrap();
387 assert_eq!(restored.value, None);
388 }
389
390 #[test]
391 fn option_u64_missing_field_deserializes_as_none() {
392 let json = serde_json::json!({});
393 let restored: TestOptionU64 = serde_json::from_value(json).unwrap();
394 assert_eq!(restored.value, None);
395 }
396
397 #[test]
398 fn u64_deserialize_from_i64_value() {
399 let json = serde_json::json!({"value": 42});
401 let restored: TestU64 = serde_json::from_value(json).unwrap();
402 assert_eq!(restored.value, 42);
403 }
404
405 #[test]
406 fn u64_deserialize_negative_i64_fails() {
407 let json = serde_json::json!({"value": -1});
409 let result = serde_json::from_value::<TestU64>(json);
410 assert!(result.is_err());
411 assert!(result.unwrap_err().to_string().contains("out of u64 range"));
412 }
413
414 #[test]
415 fn u64_deserialize_invalid_string_fails() {
416 let json = serde_json::json!({"value": "not_a_number"});
417 let result = serde_json::from_value::<TestU64>(json);
418 assert!(result.is_err());
419 assert!(result
420 .unwrap_err()
421 .to_string()
422 .contains("invalid u64 string"));
423 }
424
425 #[test]
426 fn i64_deserialize_u64_overflow_fails() {
427 let json = serde_json::json!({"value": u64::MAX.to_string()});
429 let result = serde_json::from_value::<TestI64>(json);
431 assert!(result.is_err());
432 }
433
434 #[test]
435 fn i64_deserialize_invalid_string_fails() {
436 let json = serde_json::json!({"value": "not_a_number"});
437 let result = serde_json::from_value::<TestI64>(json);
438 assert!(result.is_err());
439 assert!(result
440 .unwrap_err()
441 .to_string()
442 .contains("invalid i64 string"));
443 }
444
445 #[test]
446 fn platform_value_i64_stays_native() {
447 let t = TestI64 { value: i64::MAX };
448 let pv = platform_value::to_value(&t).unwrap();
449 let restored: TestI64 = platform_value::from_value(pv).unwrap();
450 assert_eq!(t, restored);
451 }
452
453 #[test]
454 fn platform_value_option_u64_round_trip() {
455 let t = TestOptionU64 {
456 value: Some(u64::MAX),
457 };
458 let pv = platform_value::to_value(&t).unwrap();
459 let restored: TestOptionU64 = platform_value::from_value(pv).unwrap();
460 assert_eq!(t, restored);
461 }
462
463 #[test]
464 fn platform_value_option_i64_round_trip() {
465 let t = TestOptionI64 {
466 value: Some(i64::MIN),
467 };
468 let pv = platform_value::to_value(&t).unwrap();
469 let restored: TestOptionI64 = platform_value::from_value(pv).unwrap();
470 assert_eq!(t, restored);
471 }
472
473 #[test]
474 fn option_u64_small_value_stays_number() {
475 let t = TestOptionU64 { value: Some(42) };
476 let json = serde_json::to_value(&t).unwrap();
477 assert!(json["value"].is_number());
478
479 let restored: TestOptionU64 = serde_json::from_value(json).unwrap();
480 assert_eq!(t, restored);
481 }
482
483 #[test]
484 fn option_i64_small_value_stays_number() {
485 let t = TestOptionI64 { value: Some(-42) };
486 let json = serde_json::to_value(&t).unwrap();
487 assert!(json["value"].is_number());
488
489 let restored: TestOptionI64 = serde_json::from_value(json).unwrap();
490 assert_eq!(t, restored);
491 }
492
493 #[test]
494 fn tagged_enum_with_u64_round_trip() {
495 #[derive(Debug, PartialEq, Serialize, Deserialize)]
496 #[serde(tag = "$formatVersion")]
497 enum Versioned {
498 #[serde(rename = "0")]
499 V0(TestU64),
500 }
501
502 let v = Versioned::V0(TestU64 { value: u64::MAX });
503 let json = serde_json::to_value(&v).unwrap();
504 assert_eq!(json["$formatVersion"], "0");
505 assert!(json["value"].is_string());
506
507 let restored: Versioned = serde_json::from_value(json).unwrap();
508 assert_eq!(v, restored);
509 }
510
511 #[test]
514 fn option_i64_some_safe_value_stays_number() {
515 let t = TestOptionI64 { value: Some(1000) };
516 let json = serde_json::to_value(&t).unwrap();
517 assert!(json["value"].is_number());
518 assert_eq!(json["value"].as_i64().unwrap(), 1000);
519
520 let restored: TestOptionI64 = serde_json::from_value(json).unwrap();
521 assert_eq!(t, restored);
522 }
523
524 #[test]
525 fn option_i64_some_unsafe_positive_becomes_string() {
526 let unsafe_val = (JS_MAX_SAFE_INTEGER + 1) as i64;
528 let t = TestOptionI64 {
529 value: Some(unsafe_val),
530 };
531 let json = serde_json::to_value(&t).unwrap();
532 assert!(json["value"].is_string());
533
534 let restored: TestOptionI64 = serde_json::from_value(json).unwrap();
535 assert_eq!(t, restored);
536 }
537
538 #[test]
539 fn option_i64_some_unsafe_negative_becomes_string() {
540 let unsafe_neg = -(JS_MAX_SAFE_INTEGER as i64) - 1;
542 let t = TestOptionI64 {
543 value: Some(unsafe_neg),
544 };
545 let json = serde_json::to_value(&t).unwrap();
546 assert!(json["value"].is_string());
547
548 let restored: TestOptionI64 = serde_json::from_value(json).unwrap();
549 assert_eq!(t, restored);
550 }
551
552 #[test]
555 fn u64_exactly_at_max_safe_integer_round_trip() {
556 let t = TestU64 {
557 value: JS_MAX_SAFE_INTEGER,
558 };
559 let json = serde_json::to_value(&t).unwrap();
560 assert!(json["value"].is_number());
561
562 let restored: TestU64 = serde_json::from_value(json).unwrap();
563 assert_eq!(t, restored);
564 }
565
566 #[test]
567 fn u64_one_above_max_safe_integer_round_trip() {
568 let t = TestU64 {
569 value: JS_MAX_SAFE_INTEGER + 1,
570 };
571 let json = serde_json::to_value(&t).unwrap();
572 assert!(json["value"].is_string());
573 assert_eq!(
574 json["value"].as_str().unwrap(),
575 (JS_MAX_SAFE_INTEGER + 1).to_string()
576 );
577
578 let restored: TestU64 = serde_json::from_value(json).unwrap();
579 assert_eq!(t, restored);
580 }
581
582 #[test]
583 fn i64_exactly_at_positive_safe_boundary_stays_number() {
584 let t = TestI64 {
585 value: JS_MAX_SAFE_INTEGER as i64,
586 };
587 let json = serde_json::to_value(&t).unwrap();
588 assert!(json["value"].is_number());
589
590 let restored: TestI64 = serde_json::from_value(json).unwrap();
591 assert_eq!(t, restored);
592 }
593
594 #[test]
595 fn i64_one_above_positive_safe_boundary_becomes_string() {
596 let t = TestI64 {
597 value: JS_MAX_SAFE_INTEGER as i64 + 1,
598 };
599 let json = serde_json::to_value(&t).unwrap();
600 assert!(json["value"].is_string());
601
602 let restored: TestI64 = serde_json::from_value(json).unwrap();
603 assert_eq!(t, restored);
604 }
605
606 #[test]
607 fn i64_exactly_at_negative_safe_boundary_stays_number() {
608 let t = TestI64 {
609 value: -(JS_MAX_SAFE_INTEGER as i64),
610 };
611 let json = serde_json::to_value(&t).unwrap();
612 assert!(json["value"].is_number());
613
614 let restored: TestI64 = serde_json::from_value(json).unwrap();
615 assert_eq!(t, restored);
616 }
617
618 #[test]
619 fn i64_one_below_negative_safe_boundary_becomes_string() {
620 let t = TestI64 {
621 value: -(JS_MAX_SAFE_INTEGER as i64) - 1,
622 };
623 let json = serde_json::to_value(&t).unwrap();
624 assert!(json["value"].is_string());
625
626 let restored: TestI64 = serde_json::from_value(json).unwrap();
627 assert_eq!(t, restored);
628 }
629
630 #[test]
633 fn u64_zero_stays_number() {
634 let t = TestU64 { value: 0 };
635 let json = serde_json::to_value(&t).unwrap();
636 assert!(json["value"].is_number());
637 assert_eq!(json["value"].as_u64().unwrap(), 0);
638
639 let restored: TestU64 = serde_json::from_value(json).unwrap();
640 assert_eq!(t, restored);
641 }
642
643 #[test]
644 fn i64_zero_stays_number() {
645 let t = TestI64 { value: 0 };
646 let json = serde_json::to_value(&t).unwrap();
647 assert!(json["value"].is_number());
648 assert_eq!(json["value"].as_i64().unwrap(), 0);
649
650 let restored: TestI64 = serde_json::from_value(json).unwrap();
651 assert_eq!(t, restored);
652 }
653
654 #[test]
655 fn i64_negative_one_stays_number() {
656 let t = TestI64 { value: -1 };
657 let json = serde_json::to_value(&t).unwrap();
658 assert!(json["value"].is_number());
659
660 let restored: TestI64 = serde_json::from_value(json).unwrap();
661 assert_eq!(t, restored);
662 }
663
664 #[test]
665 fn option_i64_zero_round_trip() {
666 let t = TestOptionI64 { value: Some(0) };
667 let json = serde_json::to_value(&t).unwrap();
668 assert!(json["value"].is_number());
669
670 let restored: TestOptionI64 = serde_json::from_value(json).unwrap();
671 assert_eq!(t, restored);
672 }
673
674 #[test]
675 fn option_u64_zero_round_trip() {
676 let t = TestOptionU64 { value: Some(0) };
677 let json = serde_json::to_value(&t).unwrap();
678 assert!(json["value"].is_number());
679
680 let restored: TestOptionU64 = serde_json::from_value(json).unwrap();
681 assert_eq!(t, restored);
682 }
683
684 #[test]
685 fn option_u64_at_max_safe_integer_stays_number() {
686 let t = TestOptionU64 {
687 value: Some(JS_MAX_SAFE_INTEGER),
688 };
689 let json = serde_json::to_value(&t).unwrap();
690 assert!(json["value"].is_number());
691
692 let restored: TestOptionU64 = serde_json::from_value(json).unwrap();
693 assert_eq!(t, restored);
694 }
695
696 #[test]
697 fn option_u64_above_max_safe_integer_becomes_string() {
698 let t = TestOptionU64 {
699 value: Some(JS_MAX_SAFE_INTEGER + 1),
700 };
701 let json = serde_json::to_value(&t).unwrap();
702 assert!(json["value"].is_string());
703
704 let restored: TestOptionU64 = serde_json::from_value(json).unwrap();
705 assert_eq!(t, restored);
706 }
707
708 #[test]
709 fn option_i64_at_positive_safe_boundary_stays_number() {
710 let t = TestOptionI64 {
711 value: Some(JS_MAX_SAFE_INTEGER as i64),
712 };
713 let json = serde_json::to_value(&t).unwrap();
714 assert!(json["value"].is_number());
715
716 let restored: TestOptionI64 = serde_json::from_value(json).unwrap();
717 assert_eq!(t, restored);
718 }
719
720 #[test]
721 fn option_i64_above_positive_safe_boundary_becomes_string() {
722 let t = TestOptionI64 {
723 value: Some(JS_MAX_SAFE_INTEGER as i64 + 1),
724 };
725 let json = serde_json::to_value(&t).unwrap();
726 assert!(json["value"].is_string());
727
728 let restored: TestOptionI64 = serde_json::from_value(json).unwrap();
729 assert_eq!(t, restored);
730 }
731
732 #[test]
733 fn option_i64_at_negative_safe_boundary_stays_number() {
734 let t = TestOptionI64 {
735 value: Some(-(JS_MAX_SAFE_INTEGER as i64)),
736 };
737 let json = serde_json::to_value(&t).unwrap();
738 assert!(json["value"].is_number());
739
740 let restored: TestOptionI64 = serde_json::from_value(json).unwrap();
741 assert_eq!(t, restored);
742 }
743
744 #[test]
745 fn option_i64_below_negative_safe_boundary_becomes_string() {
746 let t = TestOptionI64 {
747 value: Some(-(JS_MAX_SAFE_INTEGER as i64) - 1),
748 };
749 let json = serde_json::to_value(&t).unwrap();
750 assert!(json["value"].is_string());
751
752 let restored: TestOptionI64 = serde_json::from_value(json).unwrap();
753 assert_eq!(t, restored);
754 }
755
756 #[test]
757 fn platform_value_option_i64_none_round_trip() {
758 let t = TestOptionI64 { value: None };
759 let pv = platform_value::to_value(&t).unwrap();
760 let restored: TestOptionI64 = platform_value::from_value(pv).unwrap();
761 assert_eq!(t, restored);
762 }
763
764 #[test]
765 fn platform_value_option_u64_none_round_trip() {
766 let t = TestOptionU64 { value: None };
767 let pv = platform_value::to_value(&t).unwrap();
768 let restored: TestOptionU64 = platform_value::from_value(pv).unwrap();
769 assert_eq!(t, restored);
770 }
771
772 #[test]
773 fn u64_deserialize_from_string_number() {
774 let json = serde_json::json!({"value": "42"});
776 let restored: TestU64 = serde_json::from_value(json).unwrap();
777 assert_eq!(restored.value, 42);
778 }
779
780 #[test]
781 fn i64_deserialize_from_string_number() {
782 let json = serde_json::json!({"value": "-12345"});
783 let restored: TestI64 = serde_json::from_value(json).unwrap();
784 assert_eq!(restored.value, -12345);
785 }
786}