1use super::safe_integer::JS_MAX_SAFE_INTEGER;
26
27pub mod json_safe_u64_u64_map {
34 use serde::de::{self, Deserializer, MapAccess, Visitor};
35 use serde::ser::{SerializeMap, Serializer};
36 use std::collections::BTreeMap;
37
38 use super::JS_MAX_SAFE_INTEGER;
39
40 pub fn serialize<S: Serializer>(
41 map: &BTreeMap<u64, u64>,
42 serializer: S,
43 ) -> Result<S::Ok, S::Error> {
44 if serializer.is_human_readable() {
45 let mut s = serializer.serialize_map(Some(map.len()))?;
46 for (k, v) in map {
47 s.serialize_entry(
49 &k.to_string(),
50 &if *v > JS_MAX_SAFE_INTEGER {
51 serde_json::Value::String(v.to_string())
52 } else {
53 serde_json::Value::Number((*v).into())
54 },
55 )?;
56 }
57 s.end()
58 } else {
59 serde::Serialize::serialize(map, serializer)
60 }
61 }
62
63 pub fn deserialize<'de, D: Deserializer<'de>>(
64 deserializer: D,
65 ) -> Result<BTreeMap<u64, u64>, D::Error> {
66 if deserializer.is_human_readable() {
67 deserializer.deserialize_map(U64U64MapVisitor)
68 } else {
69 serde::Deserialize::deserialize(deserializer)
70 }
71 }
72
73 struct U64U64MapVisitor;
74
75 impl<'de> Visitor<'de> for U64U64MapVisitor {
76 type Value = BTreeMap<u64, u64>;
77
78 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
79 f.write_str("a map with u64 keys and u64 values (numbers or strings)")
80 }
81
82 fn visit_map<M: MapAccess<'de>>(self, mut access: M) -> Result<Self::Value, M::Error> {
83 let mut map = BTreeMap::new();
84 while let Some((key, value)) =
85 access.next_entry::<serde_json::Value, serde_json::Value>()?
86 {
87 let k = json_value_to_u64(&key).map_err(de::Error::custom)?;
88 let v = json_value_to_u64(&value).map_err(de::Error::custom)?;
89 map.insert(k, v);
90 }
91 Ok(map)
92 }
93 }
94
95 fn json_value_to_u64(v: &serde_json::Value) -> Result<u64, String> {
96 match v {
97 serde_json::Value::Number(n) => n
98 .as_u64()
99 .ok_or_else(|| format!("expected u64 number, got: {n}")),
100 serde_json::Value::String(s) => s
101 .parse::<u64>()
102 .map_err(|_| format!("invalid u64 string: {s}")),
103 other => Err(format!("expected u64 or string, got: {other}")),
104 }
105 }
106}
107
108pub mod json_safe_identifier_u64_map {
114 use platform_value::Identifier;
115 use serde::de::{self, Deserializer, MapAccess, Visitor};
116 use serde::ser::{SerializeMap, Serializer};
117 use std::collections::BTreeMap;
118
119 use super::JS_MAX_SAFE_INTEGER;
120
121 pub fn serialize<S: Serializer>(
122 map: &BTreeMap<Identifier, u64>,
123 serializer: S,
124 ) -> Result<S::Ok, S::Error> {
125 if serializer.is_human_readable() {
126 let mut s = serializer.serialize_map(Some(map.len()))?;
127 for (k, v) in map {
128 s.serialize_entry(
129 k,
130 &if *v > JS_MAX_SAFE_INTEGER {
131 serde_json::Value::String(v.to_string())
132 } else {
133 serde_json::Value::Number((*v).into())
134 },
135 )?;
136 }
137 s.end()
138 } else {
139 serde::Serialize::serialize(map, serializer)
140 }
141 }
142
143 pub fn deserialize<'de, D: Deserializer<'de>>(
144 deserializer: D,
145 ) -> Result<BTreeMap<Identifier, u64>, D::Error> {
146 if deserializer.is_human_readable() {
147 deserializer.deserialize_map(IdentifierU64MapVisitor)
148 } else {
149 serde::Deserialize::deserialize(deserializer)
150 }
151 }
152
153 struct IdentifierU64MapVisitor;
154
155 impl<'de> Visitor<'de> for IdentifierU64MapVisitor {
156 type Value = BTreeMap<Identifier, u64>;
157
158 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
159 f.write_str("a map with Identifier keys and u64 values (numbers or strings)")
160 }
161
162 fn visit_map<M: MapAccess<'de>>(self, mut access: M) -> Result<Self::Value, M::Error> {
163 let mut map = BTreeMap::new();
164 while let Some((key, value)) = access.next_entry::<Identifier, serde_json::Value>()? {
165 let v = match &value {
166 serde_json::Value::Number(n) => n
167 .as_u64()
168 .ok_or_else(|| de::Error::custom(format!("expected u64 number, got: {n}"))),
169 serde_json::Value::String(s) => s
170 .parse::<u64>()
171 .map_err(|_| de::Error::custom(format!("invalid u64 string: {s}"))),
172 other => Err(de::Error::custom(format!(
173 "expected u64 or string, got: {other}"
174 ))),
175 }?;
176 map.insert(key, v);
177 }
178 Ok(map)
179 }
180 }
181}
182
183pub mod json_safe_u64_nested_identifier_u64_map {
190 use platform_value::Identifier;
191 use serde::de::{self, Deserializer, MapAccess, Visitor};
192 use serde::ser::{SerializeMap, Serializer};
193 use std::collections::BTreeMap;
194
195 use super::JS_MAX_SAFE_INTEGER;
196
197 pub fn serialize<S: Serializer>(
198 map: &BTreeMap<u64, BTreeMap<Identifier, u64>>,
199 serializer: S,
200 ) -> Result<S::Ok, S::Error> {
201 if serializer.is_human_readable() {
202 let mut outer = serializer.serialize_map(Some(map.len()))?;
203 for (k, inner) in map {
204 let safe_inner: BTreeMap<&Identifier, serde_json::Value> = inner
205 .iter()
206 .map(|(ik, iv)| {
207 let v = if *iv > JS_MAX_SAFE_INTEGER {
208 serde_json::Value::String(iv.to_string())
209 } else {
210 serde_json::Value::Number((*iv).into())
211 };
212 (ik, v)
213 })
214 .collect();
215 outer.serialize_entry(&k.to_string(), &safe_inner)?;
216 }
217 outer.end()
218 } else {
219 serde::Serialize::serialize(map, serializer)
220 }
221 }
222
223 pub fn deserialize<'de, D: Deserializer<'de>>(
224 deserializer: D,
225 ) -> Result<BTreeMap<u64, BTreeMap<Identifier, u64>>, D::Error> {
226 if deserializer.is_human_readable() {
227 deserializer.deserialize_map(OuterMapVisitor)
228 } else {
229 serde::Deserialize::deserialize(deserializer)
230 }
231 }
232
233 struct OuterMapVisitor;
234
235 impl<'de> Visitor<'de> for OuterMapVisitor {
236 type Value = BTreeMap<u64, BTreeMap<Identifier, u64>>;
237
238 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
239 f.write_str("a nested map: u64 -> (Identifier -> u64)")
240 }
241
242 fn visit_map<M: MapAccess<'de>>(self, mut access: M) -> Result<Self::Value, M::Error> {
243 let mut map = BTreeMap::new();
244 while let Some((key_str, inner_json)) =
245 access.next_entry::<serde_json::Value, BTreeMap<Identifier, serde_json::Value>>()?
246 {
247 let k = match &key_str {
248 serde_json::Value::Number(n) => n
249 .as_u64()
250 .ok_or_else(|| de::Error::custom(format!("expected u64 key, got: {n}"))),
251 serde_json::Value::String(s) => s
252 .parse::<u64>()
253 .map_err(|_| de::Error::custom(format!("invalid u64 key: {s}"))),
254 other => Err(de::Error::custom(format!("expected u64 key, got: {other}"))),
255 }?;
256
257 let inner: BTreeMap<Identifier, u64> = inner_json
258 .into_iter()
259 .map(|(ik, iv)| {
260 let v = match &iv {
261 serde_json::Value::Number(n) => n.as_u64().ok_or_else(|| {
262 de::Error::custom(format!("expected u64 value, got: {n}"))
263 }),
264 serde_json::Value::String(s) => s
265 .parse::<u64>()
266 .map_err(|_| de::Error::custom(format!("invalid u64 string: {s}"))),
267 other => Err(de::Error::custom(format!(
268 "expected u64 or string, got: {other}"
269 ))),
270 }?;
271 Ok((ik, v))
272 })
273 .collect::<Result<_, M::Error>>()?;
274
275 map.insert(k, inner);
276 }
277 Ok(map)
278 }
279 }
280}
281
282pub mod json_safe_generic_u64_value_map {
289 use serde::de::{self, Deserializer, MapAccess, Visitor};
290 use serde::ser::{SerializeMap, Serializer};
291 use std::collections::BTreeMap;
292 use std::marker::PhantomData;
293
294 use super::JS_MAX_SAFE_INTEGER;
295
296 pub fn serialize<K, S>(map: &BTreeMap<K, u64>, serializer: S) -> Result<S::Ok, S::Error>
297 where
298 K: serde::Serialize + Ord,
299 S: Serializer,
300 {
301 if serializer.is_human_readable() {
302 let mut s = serializer.serialize_map(Some(map.len()))?;
303 for (k, v) in map {
304 s.serialize_entry(
305 k,
306 &if *v > JS_MAX_SAFE_INTEGER {
307 serde_json::Value::String(v.to_string())
308 } else {
309 serde_json::Value::Number((*v).into())
310 },
311 )?;
312 }
313 s.end()
314 } else {
315 serde::Serialize::serialize(map, serializer)
316 }
317 }
318
319 pub fn deserialize<'de, K, D>(deserializer: D) -> Result<BTreeMap<K, u64>, D::Error>
320 where
321 K: serde::Deserialize<'de> + Ord,
322 D: Deserializer<'de>,
323 {
324 if deserializer.is_human_readable() {
325 deserializer.deserialize_map(GenericU64ValueMapVisitor(PhantomData))
326 } else {
327 serde::Deserialize::deserialize(deserializer)
328 }
329 }
330
331 struct GenericU64ValueMapVisitor<K>(PhantomData<K>);
332
333 impl<'de, K> Visitor<'de> for GenericU64ValueMapVisitor<K>
334 where
335 K: serde::Deserialize<'de> + Ord,
336 {
337 type Value = BTreeMap<K, u64>;
338
339 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
340 f.write_str("a map with u64 values (numbers or strings)")
341 }
342
343 fn visit_map<M: MapAccess<'de>>(self, mut access: M) -> Result<Self::Value, M::Error> {
344 let mut map = BTreeMap::new();
345 while let Some((key, value)) = access.next_entry::<K, serde_json::Value>()? {
346 let v = match &value {
347 serde_json::Value::Number(n) => n
348 .as_u64()
349 .ok_or_else(|| de::Error::custom(format!("expected u64 number, got: {n}"))),
350 serde_json::Value::String(s) => s
351 .parse::<u64>()
352 .map_err(|_| de::Error::custom(format!("invalid u64 string: {s}"))),
353 other => Err(de::Error::custom(format!(
354 "expected u64 or string, got: {other}"
355 ))),
356 }?;
357 map.insert(key, v);
358 }
359 Ok(map)
360 }
361 }
362}
363
364#[cfg(test)]
365mod tests {
366 use super::*;
367 use platform_value::string_encoding::Encoding;
368 use platform_value::Identifier;
369 use serde::{Deserialize, Serialize};
370 use std::collections::BTreeMap;
371
372 #[derive(Debug, PartialEq, Serialize, Deserialize)]
373 struct TestIdentifierU64Map {
374 #[serde(with = "json_safe_identifier_u64_map")]
375 data: BTreeMap<Identifier, u64>,
376 }
377
378 #[derive(Debug, PartialEq, Serialize, Deserialize)]
379 struct TestU64U64Map {
380 #[serde(with = "json_safe_u64_u64_map")]
381 data: BTreeMap<u64, u64>,
382 }
383
384 #[derive(Debug, PartialEq, Serialize, Deserialize)]
385 struct TestNestedMap {
386 #[serde(with = "json_safe_u64_nested_identifier_u64_map")]
387 data: BTreeMap<u64, BTreeMap<Identifier, u64>>,
388 }
389
390 #[test]
391 fn identifier_u64_map_small_values_stay_numbers() {
392 let id = Identifier::random();
393 let mut data = BTreeMap::new();
394 data.insert(id, 42u64);
395 let t = TestIdentifierU64Map { data };
396 let json = serde_json::to_value(&t).unwrap();
397 let restored: TestIdentifierU64Map = serde_json::from_value(json).unwrap();
398 assert_eq!(t, restored);
399 }
400
401 #[test]
402 fn identifier_u64_map_large_values_become_strings() {
403 let id = Identifier::random();
404 let mut data = BTreeMap::new();
405 data.insert(id, u64::MAX);
406 let t = TestIdentifierU64Map { data };
407 let json = serde_json::to_value(&t).unwrap();
408
409 let map_obj = json["data"].as_object().unwrap();
411 let val = map_obj.values().next().unwrap();
412 assert!(val.is_string());
413 assert_eq!(val.as_str().unwrap(), "18446744073709551615");
414
415 let restored: TestIdentifierU64Map = serde_json::from_value(json).unwrap();
416 assert_eq!(t, restored);
417 }
418
419 #[test]
420 fn u64_u64_map_round_trip_with_large_values() {
421 let mut data = BTreeMap::new();
422 data.insert(100u64, 42u64);
423 data.insert(u64::MAX, u64::MAX);
424 let t = TestU64U64Map { data };
425 let json = serde_json::to_value(&t).unwrap();
426
427 let map_obj = json["data"].as_object().unwrap();
429 let large_val = &map_obj["18446744073709551615"];
430 assert!(large_val.is_string());
431
432 let restored: TestU64U64Map = serde_json::from_value(json).unwrap();
433 assert_eq!(t, restored);
434 }
435
436 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
437 struct CustomKey(String);
438
439 #[derive(Debug, PartialEq, Serialize, Deserialize)]
440 struct TestGenericMap {
441 #[serde(with = "json_safe_generic_u64_value_map")]
442 data: BTreeMap<CustomKey, u64>,
443 }
444
445 #[test]
446 fn generic_map_small_values_stay_numbers() {
447 let mut data = BTreeMap::new();
448 data.insert(CustomKey("alice".into()), 42u64);
449 let t = TestGenericMap { data };
450 let json = serde_json::to_value(&t).unwrap();
451
452 let val = &json["data"]["alice"];
453 assert!(val.is_number());
454 assert_eq!(val.as_u64().unwrap(), 42);
455
456 let restored: TestGenericMap = serde_json::from_value(json).unwrap();
457 assert_eq!(t, restored);
458 }
459
460 #[test]
461 fn generic_map_large_values_become_strings() {
462 let mut data = BTreeMap::new();
463 data.insert(CustomKey("bob".into()), u64::MAX);
464 let t = TestGenericMap { data };
465 let json = serde_json::to_value(&t).unwrap();
466
467 let val = &json["data"]["bob"];
468 assert!(val.is_string());
469 assert_eq!(val.as_str().unwrap(), "18446744073709551615");
470
471 let restored: TestGenericMap = serde_json::from_value(json).unwrap();
472 assert_eq!(t, restored);
473 }
474
475 #[test]
476 fn generic_map_mixed_values_round_trip() {
477 let mut data = BTreeMap::new();
478 data.insert(CustomKey("small".into()), 100u64);
479 data.insert(CustomKey("large".into()), u64::MAX);
480 let t = TestGenericMap { data };
481 let json = serde_json::to_value(&t).unwrap();
482
483 assert!(json["data"]["small"].is_number());
485 assert!(json["data"]["large"].is_string());
486
487 let restored: TestGenericMap = serde_json::from_value(json).unwrap();
488 assert_eq!(t, restored);
489 }
490
491 #[test]
492 fn u64_u64_map_small_values_stay_numbers() {
493 let mut data = BTreeMap::new();
494 data.insert(5u64, 10u64);
495 let t = TestU64U64Map { data };
496 let json = serde_json::to_value(&t).unwrap();
497 let map_obj = json["data"].as_object().unwrap();
498 let val = &map_obj["5"];
499 assert!(val.is_number());
500
501 let restored: TestU64U64Map = serde_json::from_value(json).unwrap();
502 assert_eq!(t, restored);
503 }
504
505 #[test]
506 fn u64_u64_map_empty_round_trip() {
507 let t = TestU64U64Map {
508 data: BTreeMap::new(),
509 };
510 let json = serde_json::to_value(&t).unwrap();
511 let restored: TestU64U64Map = serde_json::from_value(json).unwrap();
512 assert_eq!(t, restored);
513 }
514
515 #[test]
516 fn identifier_u64_map_empty_round_trip() {
517 let t = TestIdentifierU64Map {
518 data: BTreeMap::new(),
519 };
520 let json = serde_json::to_value(&t).unwrap();
521 let restored: TestIdentifierU64Map = serde_json::from_value(json).unwrap();
522 assert_eq!(t, restored);
523 }
524
525 #[test]
526 fn platform_value_generic_map_round_trip() {
527 let mut data = BTreeMap::new();
528 data.insert(CustomKey("x".into()), u64::MAX);
529 let t = TestGenericMap { data };
530 let pv = platform_value::to_value(&t).unwrap();
531 let restored: TestGenericMap = platform_value::from_value(pv).unwrap();
532 assert_eq!(t, restored);
533 }
534
535 #[test]
536 fn u64_u64_map_invalid_value_type_fails() {
537 let json = serde_json::json!({"data": {"1": true}});
538 let result = serde_json::from_value::<TestU64U64Map>(json);
539 assert!(result.is_err());
540 }
541
542 #[test]
543 fn u64_u64_map_invalid_value_string_fails() {
544 let json = serde_json::json!({"data": {"1": "not_a_number"}});
545 let result = serde_json::from_value::<TestU64U64Map>(json);
546 assert!(result.is_err());
547 }
548
549 #[test]
550 fn identifier_u64_map_invalid_value_type_fails() {
551 let id = Identifier::random();
552 let json = serde_json::json!({"data": {id.to_string(Encoding::Base58): [1, 2, 3]}});
553 let result = serde_json::from_value::<TestIdentifierU64Map>(json);
554 assert!(result.is_err());
555 }
556
557 #[test]
558 fn nested_map_empty_inner_round_trip() {
559 let mut data = BTreeMap::new();
560 data.insert(1u64, BTreeMap::new());
561 let t = TestNestedMap { data };
562 let json = serde_json::to_value(&t).unwrap();
563 let restored: TestNestedMap = serde_json::from_value(json).unwrap();
564 assert_eq!(t, restored);
565 }
566
567 #[test]
568 fn nested_map_round_trip() {
569 let id = Identifier::random();
570 let mut inner = BTreeMap::new();
571 inner.insert(id, u64::MAX);
572 let mut data = BTreeMap::new();
573 data.insert(1735689600000u64, inner);
574 let t = TestNestedMap { data };
575 let json = serde_json::to_value(&t).unwrap();
576 let restored: TestNestedMap = serde_json::from_value(json).unwrap();
577 assert_eq!(t, restored);
578 }
579}