ep_core/
serde.rs

1//! Custom serde serialization helpers
2
3/// Serialization shim for arbitrary arrays that is consistent with `polkadot-js`'s implementation.
4///
5/// `polkadot-js` sends us a `0x01020304`, but the default rust implementation for arrays expects a
6/// `[0x01, 0x02, 0x03, 0x04]`. Here, we use a similar serialization as substrate uses for `vec`,
7/// but we transform it to an array before returning.
8pub mod serialize_array {
9	use impl_serde::serialize::{deserialize_check_len, ExpectedLen};
10	use serde::Deserializer;
11
12	// default serialize is fine
13	pub use impl_serde::serialize::serialize;
14
15	pub use deserialize_array as deserialize;
16
17	pub fn deserialize_array<'de, D, const T: usize>(deserializer: D) -> Result<[u8; T], D::Error>
18	where
19		D: Deserializer<'de>,
20	{
21		// All hail the stable const generics!
22		let mut arr = [0u8; T];
23		deserialize_check_len(deserializer, ExpectedLen::Exact(&mut arr[..]))?;
24
25		Ok(arr)
26	}
27}
28
29/// Serialization shim for fixed point numbers that is consistent with `polkadot-js`'s
30/// implementation.
31///
32/// This is needed in particular for fixed point types that map to a i-/u128, as serde has problems
33/// with it: https://github.com/paritytech/substrate/issues/4641
34pub mod serialize_fixed {
35	use fixed::traits::Fixed;
36	use serde::{de::Error, Deserializer};
37
38	use impl_serde::serde::Deserialize;
39
40	#[cfg(not(feature = "std"))]
41	extern crate alloc;
42
43	#[cfg(not(feature = "std"))]
44	use alloc::string::String;
45	#[cfg(not(feature = "std"))]
46	use alloc::string::ToString;
47
48	pub use deserialize_fixed as deserialize;
49	pub use serialize_fixed as serialize;
50
51	pub fn serialize_fixed<S, F: Fixed>(f: &F, s: S) -> Result<S::Ok, S::Error>
52	where
53		S: serde::Serializer,
54	{
55		s.serialize_str(&f.to_string())
56	}
57
58	pub fn deserialize_fixed<'de, D, F: Fixed>(d: D) -> Result<F, D::Error>
59	where
60		D: Deserializer<'de>,
61	{
62		let s = String::deserialize(d)?;
63		F::from_str(&s).map_err(D::Error::custom)
64	}
65}
66
67#[cfg(test)]
68mod tests {
69	use super::{serialize_array, serialize_fixed};
70	use fixed::{traits::Fixed, types::I64F64};
71
72	fn deserialize_array<const T: usize>(arr: &str) -> [u8; T] {
73		let mut der = serde_json::Deserializer::new(serde_json::de::StrRead::new(arr));
74		serialize_array::deserialize(&mut der).unwrap()
75	}
76
77	fn serialize_array<const T: usize>(arr: [u8; T]) -> String {
78		let mut v = vec![];
79
80		let mut ser = serde_json::Serializer::new(std::io::Cursor::new(&mut v));
81		serialize_array::serialize(&arr, &mut ser).unwrap();
82
83		String::from_utf8(v).unwrap()
84	}
85
86	fn serialize_fixed_point<F: Fixed>(f: F) -> String {
87		let mut v = vec![];
88
89		let mut ser = serde_json::Serializer::new(std::io::Cursor::new(&mut v));
90		serialize_fixed::serialize(&f, &mut ser).unwrap();
91
92		String::from_utf8(v).unwrap()
93	}
94
95	fn deserialize_fixed_point<F: Fixed>(f: &str) -> F {
96		let mut der = serde_json::Deserializer::new(serde_json::de::StrRead::new(f));
97		serialize_fixed::deserialize(&mut der).unwrap()
98	}
99
100	#[test]
101	fn deserialize_array_works() {
102		assert_eq!(deserialize_array("\"0x0000\""), [0x00, 0x00]);
103		assert_eq!(deserialize_array("\"0x0100\""), [0x01, 0x00]);
104		assert_eq!(deserialize_array("\"0x0010\""), [0x00, 0x10]);
105	}
106
107	#[test]
108	fn serialize_array_works() {
109		assert_eq!(serialize_array([0x00, 0x00]), "\"0x0000\"".to_owned());
110		assert_eq!(serialize_array([0x01, 0x00]), "\"0x0100\"".to_owned());
111		assert_eq!(serialize_array([0x00, 0x10]), "\"0x0010\"".to_owned());
112	}
113
114	#[test]
115	fn serialize_fixed_works() {
116		assert_eq!(
117			serialize_fixed_point(I64F64::from_num(18.680_877_685_546_87)),
118			"\"18.6808776855468714473\"".to_owned()
119		);
120
121		assert_eq!(
122			serialize_fixed_point(I64F64::from_num(0.680_877_685_546_871_4)),
123			"\"0.6808776855468714473\"".to_owned()
124		);
125
126		assert_eq!(serialize_fixed_point(I64F64::from_num(1)), "\"1\"".to_owned());
127	}
128
129	#[test]
130	fn deserialize_fixed_works() {
131		assert_eq!(
132			deserialize_fixed_point::<I64F64>("\"18.6808776855468714473\""),
133			I64F64::from_num(18.680_877_685_546_87)
134		);
135
136		assert_eq!(
137			deserialize_fixed_point::<I64F64>("\"0.6808776855468714473\""),
138			I64F64::from_num(0.680_877_685_546_871_4)
139		);
140
141		assert_eq!(deserialize_fixed_point::<I64F64>("\"1\""), I64F64::from_num(1));
142	}
143}