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