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