1use core::any::type_name;
7use serde::{de::DeserializeOwned, Serialize};
8
9use crate::Binary;
10use crate::{StdError, StdResult};
11
12pub fn from_json<T: DeserializeOwned>(value: impl AsRef<[u8]>) -> StdResult<T> {
16 serde_json::from_slice(value.as_ref()).map_err(|e| StdError::parse_err(type_name::<T>(), e))
17}
18
19pub fn to_json_vec<T>(data: &T) -> StdResult<Vec<u8>>
21where
22 T: Serialize + ?Sized,
23{
24 serde_json::to_vec(data).map_err(|e| StdError::serialize_err(type_name::<T>(), e))
25}
26
27pub fn to_json_string<T>(data: &T) -> StdResult<String>
29where
30 T: Serialize + ?Sized,
31{
32 serde_json::to_string(data).map_err(|e| StdError::serialize_err(type_name::<T>(), e))
33}
34
35pub fn to_json_binary<T>(data: &T) -> StdResult<Binary>
37where
38 T: Serialize + ?Sized,
39{
40 to_json_vec(data).map(Binary::new)
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46 use core::num::{
47 NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU128, NonZeroU16,
48 NonZeroU32, NonZeroU64, NonZeroU8,
49 };
50 use proptest::{prop_assert_eq, property_test};
51 use serde::Deserialize;
52
53 use crate::msgpack::{from_msgpack, to_msgpack_vec};
54
55 #[derive(Serialize, Deserialize, Debug, PartialEq)]
56 #[serde(rename_all = "snake_case")]
57 enum SomeMsg {
58 Refund {},
59 ReleaseAll {
60 image: String,
61 amount: u32,
62 time: u64,
63 karma: i32,
64 },
65 Cowsay {
66 text: String,
67 },
68 }
69
70 #[test]
71 fn to_json_vec_works() {
72 let msg = SomeMsg::Refund {};
73 let serialized = to_json_vec(&msg).unwrap();
74 assert_eq!(serialized, br#"{"refund":{}}"#);
75
76 let msg = SomeMsg::ReleaseAll {
77 image: "foo".to_string(),
78 amount: 42,
79 time: 9007199254740999, karma: -17,
81 };
82 let serialized = String::from_utf8(to_json_vec(&msg).unwrap()).unwrap();
83 assert_eq!(
84 serialized,
85 r#"{"release_all":{"image":"foo","amount":42,"time":9007199254740999,"karma":-17}}"#
86 );
87 }
88
89 #[test]
90 fn from_json_works() {
91 let deserialized: SomeMsg = from_json(br#"{"refund":{}}"#).unwrap();
92 assert_eq!(deserialized, SomeMsg::Refund {});
93
94 let expected = SomeMsg::ReleaseAll {
95 image: "foo".to_string(),
96 amount: 42,
97 time: 18446744073709551615,
98 karma: -17,
99 };
100 let deserialized: SomeMsg = from_json(
102 br#"{"release_all":{"image":"foo","amount":42,"time":18446744073709551615,"karma":-17}}"#,
103 )
104 .unwrap();
105 assert_eq!(deserialized, expected);
106
107 let deserialized: SomeMsg = from_json(
109 r#"{"release_all":{"image":"foo","amount":42,"time":18446744073709551615,"karma":-17}}"#,
110 )
111 .unwrap();
112 assert_eq!(deserialized, expected);
113 }
114
115 #[test]
116 fn from_json_or_binary() {
117 let msg = SomeMsg::Refund {};
118 let serialized: Binary = to_json_binary(&msg).unwrap();
119
120 let parse_binary: SomeMsg = from_json(&serialized).unwrap();
121 assert_eq!(parse_binary, msg);
122
123 let parse_slice: SomeMsg = from_json(serialized.as_slice()).unwrap();
124 assert_eq!(parse_slice, msg);
125 }
126
127 #[test]
128 fn to_json_vec_works_for_special_chars() {
129 let msg = SomeMsg::Cowsay {
130 text: "foo\"bar\\\"bla".to_string(),
131 };
132 let serialized = String::from_utf8(to_json_vec(&msg).unwrap()).unwrap();
133 assert_eq!(serialized, r#"{"cowsay":{"text":"foo\"bar\\\"bla"}}"#);
134 }
135
136 #[test]
137 fn from_json_works_for_special_chars() {
138 let deserialized: SomeMsg = from_json(br#"{"cowsay":{"text":"foo\"bar\\\"bla"}}"#).unwrap();
139 assert_eq!(
140 deserialized,
141 SomeMsg::Cowsay {
142 text: "foo\"bar\\\"bla".to_string(),
143 }
144 );
145 }
146
147 #[test]
148 fn to_json_string_works() {
149 let msg = SomeMsg::Refund {};
150 let serialized = to_json_string(&msg).unwrap();
151 assert_eq!(serialized, r#"{"refund":{}}"#);
152
153 let msg = SomeMsg::ReleaseAll {
154 image: "foo".to_string(),
155 amount: 42,
156 time: 9007199254740999, karma: -17,
158 };
159 let serialized = to_json_string(&msg).unwrap();
160 assert_eq!(
161 serialized,
162 r#"{"release_all":{"image":"foo","amount":42,"time":9007199254740999,"karma":-17}}"#
163 );
164 }
165
166 macro_rules! test_integer {
167 ($($ty:ty),+$(,)?) => {
168 $(
169 ::paste::paste! {
170 #[property_test]
171 fn [<test_ $ty:snake:lower _encoding>](input: $ty) {
172 let primitive = input.get();
173
174 let serialized = to_json_string(&input).unwrap();
176 let serialized_primitive = to_json_string(&primitive).unwrap();
177 prop_assert_eq!(serialized.as_str(), serialized_primitive.as_str());
178
179 let deserialized: $ty = from_json(serialized_primitive).unwrap();
181 assert_eq!(deserialized, input);
182
183 assert!(from_json::<$ty>("0").is_err());
185
186 let serialized = to_msgpack_vec(&input).unwrap();
188 let serialized_primitive = to_msgpack_vec(&primitive).unwrap();
189 prop_assert_eq!(serialized.as_slice(), serialized_primitive.as_slice());
190
191 let deserialized: $ty = from_msgpack(&serialized_primitive).unwrap();
193 prop_assert_eq!(deserialized, input);
194 }
195 }
196 )+
197 };
198 }
199
200 test_integer! {
201 NonZeroU8,
202 NonZeroU16,
203 NonZeroU32,
204 NonZeroU64,
205 NonZeroU128,
206 }
207
208 test_integer! {
209 NonZeroI8,
210 NonZeroI16,
211 NonZeroI32,
212 NonZeroI64,
213 NonZeroI128,
214 }
215}