1use rquickjs::{Ctx, Value};
2use serde::Serialize;
3use serde::de::DeserializeOwned;
4
5#[doc(inline)]
6pub use crate::de::Deserializer;
7#[doc(inline)]
8pub use crate::err::{Error, Result};
9#[doc(inline)]
10pub use crate::ser::Serializer;
11
12pub mod de;
13pub mod err;
14pub mod ser;
15#[cfg(test)]
16mod test;
17mod utils;
18
19pub const MAX_SAFE_INTEGER: i64 = 2_i64.pow(53) - 1;
21
22pub const MIN_SAFE_INTEGER: i64 = -MAX_SAFE_INTEGER;
24
25#[inline]
67pub fn to_value<T>(context: Ctx<'_>, value: T) -> Result<Value<'_>>
68where
69 T: Serialize,
70{
71 let mut serializer = Serializer::from_context(context)?;
72 value.serialize(&mut serializer)?;
73 Ok(serializer.value)
74}
75
76#[inline]
122pub fn from_value<T>(value: Value) -> Result<T>
123where
124 T: DeserializeOwned,
125{
126 let mut deserializer = Deserializer::from(value);
127 T::deserialize(&mut deserializer)
128}
129
130pub fn from_value_strict<T>(value: Value) -> Result<T>
136where
137 T: DeserializeOwned,
138{
139 let mut deserializer = Deserializer::from(value).with_strict();
140 T::deserialize(&mut deserializer)
141}
142
143#[cfg(test)]
144mod tests {
145 use std::collections::BTreeMap;
146
147 use quickcheck::quickcheck;
148 use serde::de::DeserializeOwned;
149 use serde::{Deserialize, Serialize};
150
151 use crate::de::Deserializer as ValueDeserializer;
152 use crate::err::Result;
153 use crate::ser::Serializer as ValueSerializer;
154 use crate::test::Runtime;
155 use crate::{MAX_SAFE_INTEGER, MIN_SAFE_INTEGER};
156
157 quickcheck! {
158 fn test_str(expected: String) -> Result<bool> {
159 let actual = do_roundtrip::<_, String>(&expected);
160 Ok(expected == actual)
161 }
162
163 fn test_u8(expected: u8) -> Result<bool> {
164 let actual = do_roundtrip::<_, u8>(&expected);
165 Ok(expected == actual)
166 }
167
168 fn test_u16(expected: u16) -> Result<bool> {
169 let actual = do_roundtrip::<_, u16>(&expected);
170 Ok(expected == actual)
171 }
172
173 fn test_f32(expected: f32) -> quickcheck::TestResult {
174 if expected.is_nan() {
175 return quickcheck::TestResult::discard();
176 }
177
178 let actual = do_roundtrip::<_, f32>(&expected);
179 quickcheck::TestResult::from_bool(expected == actual)
180 }
181
182 fn test_i32(expected: i32) -> Result<bool> {
183 let actual = do_roundtrip::<_, i32>(&expected);
184 Ok(expected == actual)
185 }
186
187 fn test_i64(expected: i64) -> Result<bool> {
195 if (MIN_SAFE_INTEGER..=MAX_SAFE_INTEGER).contains(&expected) {
196 let actual = do_roundtrip::<_, i64>(&expected);
197 Ok(expected == actual)
198 } else {
199 let expected_f64 = expected as f64;
200 let actual = do_roundtrip::<_, f64>(&expected_f64);
201 Ok(expected_f64 == actual)
202 }
203 }
204
205 fn test_u32(expected: u32) -> Result<bool> {
206 let actual = do_roundtrip::<_, u32>(&expected);
207 Ok(expected == actual)
208 }
209
210 fn test_u64(expected: u64) -> Result<bool> {
218 if expected <= MAX_SAFE_INTEGER as u64 {
219 let actual = do_roundtrip::<_, u64>(&expected);
220 Ok(expected == actual)
221 } else {
222 let expected_f64 = expected as f64;
223 let actual = do_roundtrip::<_, f64>(&expected_f64);
224 Ok(expected_f64 == actual)
225 }
226 }
227
228 fn test_bool(expected: bool) -> Result<bool> {
229 let actual = do_roundtrip::<_, bool>(&expected);
230 Ok(expected == actual)
231 }
232 }
233
234 #[test]
235 fn test_map() {
236 let mut expected = BTreeMap::<String, String>::new();
237 expected.insert("foo".to_string(), "bar".to_string());
238 expected.insert("hello".to_string(), "world".to_string());
239
240 let actual = do_roundtrip::<_, BTreeMap<String, String>>(&expected);
241
242 assert_eq!(expected, actual);
243 }
244
245 #[test]
246 fn test_struct_into_map() {
247 #[derive(Debug, Serialize, Deserialize, PartialEq)]
248 struct MyObject {
249 foo: String,
250 bar: u32,
251 }
252 let expected = MyObject {
253 foo: "hello".to_string(),
254 bar: 1337,
255 };
256
257 let actual = do_roundtrip::<_, MyObject>(&expected);
258
259 assert_eq!(expected, actual);
260 }
261
262 #[test]
263 fn test_nested_maps() {
264 let mut expected = BTreeMap::<String, BTreeMap<String, String>>::new();
265 let mut a = BTreeMap::new();
266 a.insert("foo".to_string(), "bar".to_string());
267 a.insert("hello".to_string(), "world".to_string());
268 let mut b = BTreeMap::new();
269 b.insert("toto".to_string(), "titi".to_string());
270 expected.insert("aaa".to_string(), a);
271 expected.insert("bbb".to_string(), b);
272
273 let actual = do_roundtrip::<_, BTreeMap<String, BTreeMap<String, String>>>(&expected);
274
275 assert_eq!(expected, actual);
276 }
277
278 #[test]
279 fn test_nested_structs_into_maps() {
280 #[derive(Debug, Serialize, Deserialize, PartialEq)]
281 struct MyObjectB {
282 toto: String,
283 titi: i32,
284 }
285
286 #[derive(Debug, Serialize, Deserialize, PartialEq)]
287 struct MyObjectA {
288 foo: String,
289 bar: u32,
290 b: MyObjectB,
291 }
292 let expected = MyObjectA {
293 foo: "hello".to_string(),
294 bar: 1337,
295 b: MyObjectB {
296 toto: "world".to_string(),
297 titi: -42,
298 },
299 };
300
301 let actual = do_roundtrip::<_, MyObjectA>(&expected);
302
303 assert_eq!(expected, actual);
304 }
305
306 #[test]
307 fn test_sequence() {
308 let expected = vec!["hello".to_string(), "world".to_string()];
309
310 let actual = do_roundtrip::<_, Vec<String>>(&expected);
311
312 assert_eq!(expected, actual);
313 }
314
315 #[test]
316 fn test_nested_sequences() {
317 let mut expected = Vec::new();
318 let a = vec!["foo".to_string(), "bar".to_string()];
319 let b = vec!["toto".to_string(), "tata".to_string()];
320 expected.push(a);
321 expected.push(b);
322
323 let actual = do_roundtrip::<_, Vec<Vec<String>>>(&expected);
324
325 assert_eq!(expected, actual);
326 }
327
328 #[test]
329 fn test_sanity() {
330 #[derive(Debug, Serialize, Deserialize, PartialEq)]
331 struct MyObject {
332 a: u8,
333 b: u16,
334 c: u32,
335 d: u64,
336 e: i8,
337 f: i16,
338 g: i32,
339 h: i64,
340 i: f32,
341 j: f64,
342 k: String,
343 l: bool,
344 m: BTreeMap<String, u32>,
345 n: Vec<u32>,
346 o: BTreeMap<String, BTreeMap<String, u32>>,
347 p: Vec<Vec<u32>>,
348 bb: MyObjectB,
349 }
350
351 #[derive(Debug, Serialize, Deserialize, PartialEq)]
352 struct MyObjectB {
353 a: u32,
354 cc: MyObjectC,
355 }
356
357 #[derive(Debug, Serialize, Deserialize, PartialEq)]
358 struct MyObjectC {
359 a: Vec<u32>,
360 b: BTreeMap<String, u32>,
361 }
362
363 let mut cc_b = BTreeMap::new();
364 cc_b.insert("a".to_string(), 123);
365 cc_b.insert("b".to_string(), 456);
366 let cc = MyObjectC {
367 a: vec![1337, 42],
368 b: cc_b,
369 };
370
371 let bb = MyObjectB { a: 789, cc };
372
373 let mut m = BTreeMap::new();
374 m.insert("a".to_string(), 123);
375 m.insert("b".to_string(), 456);
376 m.insert("c".to_string(), 789);
377
378 let mut oo = BTreeMap::new();
379 oo.insert("e".to_string(), 123);
380
381 let mut o = BTreeMap::new();
382 o.insert("d".to_string(), oo);
383
384 let expected = MyObject {
385 a: u8::MAX,
386 b: u16::MAX,
387 c: u32::MAX,
388 d: MAX_SAFE_INTEGER as u64,
389 e: i8::MAX,
390 f: i16::MAX,
391 g: i32::MAX,
392 h: MIN_SAFE_INTEGER,
393 i: f32::MAX,
394 j: f64::MAX,
395 k: "hello world".to_string(),
396 l: true,
397 m,
398 n: vec![1, 2, 3, 4, 5],
399 o,
400 p: vec![vec![1, 2], vec![3, 4, 5]],
401 bb,
402 };
403
404 let actual = do_roundtrip::<_, MyObject>(&expected);
405
406 assert_eq!(expected, actual);
407 }
408
409 fn do_roundtrip<E, A>(expected: &E) -> A
410 where
411 E: Serialize,
412 A: DeserializeOwned,
413 {
414 let rt = Runtime::default();
415 rt.context().with(|cx| {
416 let mut serializer = ValueSerializer::from_context(cx).unwrap();
417 expected.serialize(&mut serializer).unwrap();
418 let mut deserializer = ValueDeserializer::from(serializer.value);
419 A::deserialize(&mut deserializer).unwrap()
420 })
421 }
422}