alox_48/
lib.rs

1#![warn(rust_2018_idioms, clippy::all, clippy::pedantic)]
2#![warn(
3    missing_docs,
4    missing_debug_implementations,
5    missing_copy_implementations,
6    clippy::panic,
7    clippy::panic_in_result_fn,
8    clippy::panicking_unwrap,
9    clippy::all
10)]
11#![allow(
12    clippy::must_use_candidate,
13    clippy::missing_errors_doc,
14    clippy::cast_possible_truncation,
15    clippy::cast_sign_loss,
16    clippy::cast_lossless,
17    clippy::cast_possible_wrap,
18    unexpected_cfgs
19)]
20
21//! alox-48
22//! (short for aluminum oxide 48)
23//!
24//! alox-48 supports both full serialization and deserialization of Marshal, but generally users of this library will not be using
25//! most of Marshal's features. (Classes, Extended types, etc)
26//!
27//! However, alox-48 does NOT support object links. Object links are marshal's way of saving space,
28//! if an object was serialized already a "link" indicating when it was serialized is serialized instead.
29//!
30//! ```rb
31//! class MyClass
32//!  def initialize
33//!    @var = 1
34//!    @string = "hiya!"
35//!  end
36//! end
37//!
38//! a = MyClass.new
39//! Marshal.dump([a, a, a])
40//! # The array here has 3 indices all "pointing" to the same object.
41//! # Instead of serializing MyClass 3 times, Marshal will serialize it once and replace the other 2 occurences with object links.
42//! # When deserializing, Marshal will preserve object links and all 3 elements in the array will point to the same object.
43//! # In alox-48, this is not the case. Each index will be a "unique" ""object"".
44//! ```
45//!
46//! This behavior could be simulated with `Rc` and/or `Arc` like `thurgood`, however for the sake of ergonomics (and memory cycles)
47//! alox-48 deserializes object links as copies instead. alox-48 does not serialize object links at all.
48//!
49//! Some common terminology:
50//! - ivar: Instance variable. These are variables that are attached to an object.
51//! - instance: Not to be confused with a class instance. This is a value that is not an object with attached ivars.
52//! - userdata: A special type of object that is serialized by the `_dump` method.
53//! - userclass: A subclass of a ruby object like `Hash` or `Array`.
54//! - object: A generic ruby object. Can be anything from a string to an instance of a class.
55
56// Copyright (c) 2024 Lily Lyons
57//
58// This Source Code Form is subject to the terms of the Mozilla Public
59// License, v. 2.0. If a copy of the MPL was not distributed with this
60// file, You can obtain one at https://mozilla.org/MPL/2.0/.
61
62/// A convenience module for getting exact details about where an error occurred.
63pub mod path_to_error;
64
65pub(crate) mod tag;
66
67/// Marshal Deserialization framework and Deserializer.
68pub mod de;
69/// Marshal Serialization framework and Serializer.
70pub mod ser;
71
72mod value;
73pub use value::{from_value, to_value, Serializer as ValueSerializer, Value};
74
75mod rb_types;
76#[doc(inline)]
77pub use rb_types::{
78    Instance, Object, RbArray, RbFields, RbHash, RbString, RbStruct, Sym, Symbol, Userdata,
79};
80
81#[doc(inline)]
82pub use de::{
83    ArrayAccess, Deserialize, Deserializer, DeserializerTrait, Error as DeError, HashAccess,
84    InstanceAccess, IvarAccess, Result as DeResult, Visitor, VisitorInstance, VisitorOption,
85};
86#[doc(inline)]
87pub use ser::{
88    ByteString as SerializeByteString, Error as SerError, Result as SerResult, Serialize,
89    SerializeArray, SerializeHash, SerializeIvars, Serializer, SerializerTrait,
90};
91
92#[cfg(feature = "derive")]
93#[doc(inline)]
94pub use alox_48_derive::{Deserialize, Serialize};
95
96/// Deserialize data from some bytes.
97/// It's a convenience function over [`Deserializer::new`] and [`Deserialize::deserialize`].
98#[allow(clippy::missing_errors_doc)]
99pub fn from_bytes<'de, T>(data: &'de [u8]) -> Result<T, DeError>
100where
101    T: Deserialize<'de>,
102{
103    let mut deserializer = Deserializer::new(data)?;
104    T::deserialize(&mut deserializer)
105}
106
107/// Serialize the type into bytes.
108///
109/// # Errors
110///
111/// Serialization errors are uncommon, and generally result from improper `Serialize` implementations or a bug in alox-48.
112pub fn to_bytes<T>(data: T) -> Result<Vec<u8>, SerError>
113where
114    T: Serialize,
115{
116    let mut serializer = Serializer::new();
117    data.serialize(&mut serializer)?;
118    Ok(serializer.output)
119}
120
121#[cfg(test)]
122mod ints {
123    #[test]
124    fn deserialize() {
125        let bytes = &[0x04, 0x08, 0x69, 0x19];
126
127        let int: u8 = crate::from_bytes(bytes).unwrap();
128
129        assert_eq!(int, 20);
130    }
131
132    #[test]
133    fn round_trip() {
134        let int = 123;
135
136        let bytes = crate::to_bytes(int).unwrap();
137
138        let int2 = crate::from_bytes(&bytes).unwrap();
139
140        assert_eq!(int, int2);
141    }
142
143    #[test]
144    fn round_trip_value() {
145        let value = crate::Value::Integer(123);
146
147        let bytes = crate::to_bytes(&value).unwrap();
148
149        let value2: crate::Value = crate::from_bytes(&bytes).unwrap();
150
151        assert_eq!(value, value2);
152    }
153
154    #[test]
155    fn negatives() {
156        let bytes = &[0x04, 0x08, 0x69, 0xfd, 0x1d, 0xf0, 0xfc];
157
158        let int: i32 = crate::from_bytes(bytes).unwrap();
159
160        assert_eq!(int, -200_675);
161    }
162}
163
164#[cfg(test)]
165mod strings {
166    #[test]
167    fn deserialize() {
168        let bytes = &[
169            0x04, 0x08, 0x49, 0x22, 0x11, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x74, 0x68, 0x65,
170            0x72, 0x65, 0x21, 0x06, 0x3a, 0x06, 0x45, 0x54,
171        ];
172
173        let str: &str = crate::from_bytes(bytes).unwrap();
174
175        assert_eq!(str, "hello there!");
176    }
177
178    #[test]
179    fn round_trip() {
180        let str = "round trip!!";
181
182        let bytes = crate::to_bytes(str).unwrap();
183
184        let str2: &str = crate::from_bytes(&bytes).unwrap();
185
186        assert_eq!(str, str2);
187    }
188
189    #[test]
190    fn weird_encoding() {
191        let bytes = &[
192            0x04, 0x08, 0x49, 0x22, 0x11, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x74, 0x68, 0x65,
193            0x72, 0x65, 0x21, 0x06, 0x3a, 0x0d, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67,
194            0x22, 0x09, 0x42, 0x69, 0x67, 0x35,
195        ];
196
197        let str: crate::Instance<crate::RbString> = crate::from_bytes(bytes).unwrap();
198
199        assert_eq!(
200            str.encoding().unwrap().as_string().unwrap().data, // this is a mess lol, i should fix it
201            "Big5".as_bytes()
202        );
203    }
204
205    #[test]
206    fn weird_encoding_round_trip() {
207        let bytes: &[_] = &[
208            0x04, 0x08, 0x49, 0x22, 0x11, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x74, 0x68, 0x65,
209            0x72, 0x65, 0x21, 0x06, 0x3a, 0x0d, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67,
210            0x22, 0x09, 0x42, 0x69, 0x67, 0x35,
211        ];
212
213        let str: crate::Instance<crate::RbString> = crate::from_bytes(bytes).unwrap();
214
215        let bytes2 = crate::to_bytes(&str).unwrap();
216
217        assert_eq!(bytes, bytes2);
218    }
219}
220
221#[cfg(test)]
222mod floats {
223    #[test]
224    fn deserialize() {
225        let bytes = &[0x04, 0x08, 0x66, 0x07, 0x31, 0x35];
226
227        let float: f64 = crate::from_bytes(bytes).unwrap();
228
229        assert!((float - 15.0).abs() < f64::EPSILON);
230    }
231
232    #[test]
233    fn round_trip() {
234        let float = 20870.15;
235
236        let bytes = crate::to_bytes(float).unwrap();
237
238        let float2: f64 = crate::from_bytes(&bytes).unwrap();
239
240        assert!((float - float2).abs() < f64::EPSILON);
241    }
242
243    #[test]
244    fn nan() {
245        let bytes = &[0x04, 0x08, 0x66, 0x08, 0x6e, 0x61, 0x6e];
246
247        let float: f64 = crate::from_bytes(bytes).unwrap();
248
249        assert!(float.is_nan());
250    }
251
252    #[test]
253    fn round_trip_nan() {
254        let float = f64::NAN;
255
256        let bytes = crate::to_bytes(float).unwrap();
257
258        let float2: f64 = crate::from_bytes(&bytes).unwrap();
259
260        assert!(float.is_nan());
261        assert_eq!(
262            bytemuck::cast::<_, u64>(float),
263            bytemuck::cast::<_, u64>(float2)
264        );
265    }
266}
267
268#[cfg(test)]
269mod arrays {
270    #[test]
271    fn deserialize() {
272        let bytes = &[
273            0x04, 0x08, 0x5b, 0x0a, 0x69, 0x00, 0x69, 0x06, 0x69, 0x07, 0x69, 0x08, 0x69, 0x09,
274        ];
275
276        let ary: Vec<u8> = crate::from_bytes(bytes).unwrap();
277
278        assert_eq!(ary, vec![0, 1, 2, 3, 4]);
279    }
280
281    #[test]
282    fn round_trip() {
283        let ary = vec!["hi!", "goodbye!", "pain"];
284
285        let bytes = crate::to_bytes(&ary).unwrap();
286        let ary2: Vec<&str> = crate::from_bytes(&bytes).unwrap();
287
288        assert_eq!(ary, ary2);
289    }
290}
291
292mod structs {
293    #[test]
294    fn deserialize_borrowed() {
295        #[derive(alox_48_derive::Deserialize, alox_48_derive::Serialize, PartialEq, Debug)]
296        #[marshal(alox_crate_path = "crate")]
297        struct Test<'d> {
298            field1: bool,
299            field2: &'d str,
300        }
301
302        let bytes = &[
303            0x04, 0x08, 0x6f, 0x3a, 0x09, 0x54, 0x65, 0x73, 0x74, 0x07, 0x3a, 0x0c, 0x40, 0x66,
304            0x69, 0x65, 0x6c, 0x64, 0x31, 0x54, 0x3a, 0x0c, 0x40, 0x66, 0x69, 0x65, 0x6c, 0x64,
305            0x32, 0x49, 0x22, 0x10, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x72,
306            0x65, 0x06, 0x3a, 0x06, 0x45, 0x54,
307        ];
308
309        let obj: Test<'_> = crate::from_bytes(bytes).unwrap();
310
311        assert_eq!(
312            obj,
313            Test {
314                field1: true,
315                field2: "hello there"
316            }
317        );
318    }
319
320    #[test]
321    fn deserialize_multi_borrowed() {
322        #[derive(alox_48_derive::Deserialize, alox_48_derive::Serialize, PartialEq, Debug)]
323        #[marshal(alox_crate_path = "crate")]
324        struct Test<'a, 'b> {
325            field1: bool,
326            field2: &'a str,
327            #[marshal(byte_string)]
328            field3: &'b [u8],
329        }
330
331        let initial = Test {
332            field1: true,
333            field2: "borrowed from the stack",
334            field3: b"also borrowed from the stack",
335        };
336
337        let bytes = crate::to_bytes(&initial).unwrap();
338        let obj: Test<'_, '_> = crate::from_bytes(&bytes).unwrap();
339
340        assert_eq!(obj, initial);
341    }
342
343    #[test]
344    fn deserialize_multi_bounds() {
345        #[derive(alox_48_derive::Deserialize, alox_48_derive::Serialize, PartialEq, Debug)]
346        #[marshal(alox_crate_path = "crate")]
347        struct Test<'a, 'b: 'a, 'c: 'a + 'b> {
348            field1: bool,
349            field2: &'a str,
350            #[marshal(byte_string)]
351            field3: &'b [u8],
352            field4: &'c str,
353        }
354
355        let initial = Test {
356            field1: true,
357            field2: "borrowed from the stack",
358            field3: b"also borrowed from the stack",
359            field4: "multiple bounds",
360        };
361
362        let bytes = crate::to_bytes(&initial).unwrap();
363        let obj: Test<'_, '_, '_> = crate::from_bytes(&bytes).unwrap();
364
365        assert_eq!(obj, initial);
366    }
367
368    #[test]
369    fn userdata() {
370        #[derive(alox_48_derive::Deserialize, Debug, PartialEq, Eq)]
371        #[marshal(alox_crate_path = "crate")]
372        #[marshal(from = "crate::Userdata")]
373        struct MyUserData {
374            field: [char; 4],
375        }
376
377        impl From<crate::Userdata> for MyUserData {
378            fn from(value: crate::Userdata) -> Self {
379                assert_eq!(value.class, "MyUserData");
380                let field = std::array::from_fn(|i| value.data[i] as char);
381                Self { field }
382            }
383        }
384        let bytes = &[
385            0x04, 0x08, 0x75, 0x3a, 0x0f, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x44, 0x61, 0x74,
386            0x61, 0x09, 0x61, 0x62, 0x63, 0x64,
387        ];
388        let data: MyUserData = crate::from_bytes(bytes).unwrap();
389
390        assert_eq!(
391            data,
392            MyUserData {
393                field: ['a', 'b', 'c', 'd']
394            }
395        );
396    }
397}
398
399#[cfg(test)]
400mod misc {
401    #[test]
402    fn symbol() {
403        let sym = crate::Symbol::from("symbol");
404
405        let bytes = crate::to_bytes(&sym).unwrap();
406
407        let sym2: crate::Symbol = crate::from_bytes(&bytes).unwrap();
408
409        assert_eq!(sym, sym2);
410    }
411
412    // Testing for zero copy symlink deserialization
413    // ALL symbols should be the same reference
414    #[test]
415    fn symlink() {
416        let bytes = &[
417            0x04, 0x08, 0x5b, 0x0a, 0x3a, 0x09, 0x74, 0x65, 0x73, 0x74, 0x3b, 0x00, 0x3b, 0x00,
418            0x3b, 0x00, 0x3b, 0x00,
419        ];
420
421        let symbols: Vec<&str> = crate::from_bytes(bytes).unwrap();
422
423        for sym in symbols.windows(2) {
424            assert_eq!(sym[0].as_ptr(), sym[1].as_ptr());
425        }
426    }
427}
428
429#[cfg(test)]
430mod value_test {
431    #[test]
432    fn untyped_object() {
433        let bytes = &[
434            0x04, 0x08, 0x6f, 0x3a, 0x09, 0x54, 0x65, 0x73, 0x74, 0x07, 0x3a, 0x0c, 0x40, 0x66,
435            0x69, 0x65, 0x6c, 0x64, 0x31, 0x54, 0x3a, 0x0c, 0x40, 0x66, 0x69, 0x65, 0x6c, 0x64,
436            0x32, 0x49, 0x22, 0x10, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x72,
437            0x65, 0x06, 0x3a, 0x06, 0x45, 0x54,
438        ];
439
440        let obj: crate::Value = crate::from_bytes(bytes).unwrap();
441        let obj = obj.into_object().unwrap();
442
443        assert_eq!(obj.class, "Test");
444        assert_eq!(obj.fields["@field1"], true);
445    }
446
447    #[test]
448    fn untyped_ivar_string() {
449        let bytes = &[
450            0x04, 0x08, 0x49, 0x22, 0x0b, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x07, 0x3a, 0x06,
451            0x45, 0x54, 0x3a, 0x0c, 0x40, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x69, 0x01, 0x7b,
452        ];
453
454        let obj: crate::Value = crate::from_bytes(bytes).unwrap();
455        let instance = obj.into_instance().unwrap();
456
457        assert_eq!(instance.value.as_ref(), "hello!");
458        assert_eq!(instance.fields["@random"], 123);
459    }
460
461    #[test]
462    fn untyped_ivar_array() {
463        let bytes = &[
464            0x04, 0x08, 0x49, 0x5b, 0x07, 0x49, 0x22, 0x09, 0x74, 0x65, 0x73, 0x74, 0x06, 0x3a,
465            0x06, 0x45, 0x54, 0x69, 0x01, 0x7b, 0x06, 0x3a, 0x0a, 0x40, 0x69, 0x76, 0x61, 0x72,
466            0x66, 0x06, 0x35,
467        ];
468
469        let obj: crate::Value = crate::from_bytes(bytes).unwrap();
470        let instance = obj.into_instance().unwrap();
471
472        let array = instance.value.as_array().unwrap();
473        assert_eq!(&array[0], "test");
474        assert_eq!(array[1], 123);
475        assert_eq!(instance.fields["@ivar"], 5.0);
476    }
477
478    #[test]
479
480    fn untyped_to_borrowed() {
481        #[derive(alox_48_derive::Deserialize, alox_48_derive::Serialize, PartialEq, Debug)]
482        #[marshal(alox_crate_path = "crate")]
483        struct Test<'d> {
484            field1: bool,
485            field2: &'d str,
486        }
487
488        let bytes = &[
489            0x04, 0x08, 0x6f, 0x3a, 0x09, 0x54, 0x65, 0x73, 0x74, 0x07, 0x3a, 0x0c, 0x40, 0x66,
490            0x69, 0x65, 0x6c, 0x64, 0x31, 0x54, 0x3a, 0x0c, 0x40, 0x66, 0x69, 0x65, 0x6c, 0x64,
491            0x32, 0x49, 0x22, 0x10, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x72,
492            0x65, 0x06, 0x3a, 0x06, 0x45, 0x54,
493        ];
494
495        let obj: crate::Value = crate::from_bytes(bytes).unwrap();
496
497        let test: Test<'_> = crate::Deserialize::deserialize(&obj).unwrap();
498
499        assert_eq!(
500            test,
501            Test {
502                field1: true,
503                field2: "hello there"
504            }
505        );
506    }
507}
508
509#[cfg(test)]
510mod round_trip {
511    use crate::{from_bytes, to_bytes, Instance, RbFields, RbHash, RbStruct, Value};
512
513    #[test]
514    fn nil() {
515        let original = Value::Nil;
516
517        let bytes = to_bytes(&original).unwrap();
518
519        let new: Value = from_bytes(&bytes).unwrap();
520
521        assert_eq!(original, new);
522    }
523
524    #[test]
525    fn bool() {
526        let original = Value::Bool(true);
527
528        let bytes = to_bytes(&original).unwrap();
529
530        let new: Value = from_bytes(&bytes).unwrap();
531
532        assert_eq!(original, new);
533    }
534
535    #[test]
536    fn float() {
537        let original = Value::Float(123.456);
538
539        let bytes = to_bytes(&original).unwrap();
540
541        let new: Value = from_bytes(&bytes).unwrap();
542
543        assert_eq!(original, new);
544    }
545
546    #[test]
547    fn integer() {
548        let original = Value::Integer(123);
549
550        let bytes = to_bytes(&original).unwrap();
551
552        let new: Value = from_bytes(&bytes).unwrap();
553
554        assert_eq!(original, new);
555    }
556
557    #[test]
558    fn string() {
559        let original = Value::String("round trip".into());
560
561        let bytes = to_bytes(&original).unwrap();
562
563        let new: Value = from_bytes(&bytes).unwrap();
564
565        assert_eq!(original, new);
566    }
567
568    #[test]
569    fn symbol() {
570        let original = Value::Symbol("round_trip".into());
571
572        let bytes = to_bytes(&original).unwrap();
573
574        let new: Value = from_bytes(&bytes).unwrap();
575
576        assert_eq!(original, new);
577    }
578
579    #[test]
580    fn array() {
581        let original = Value::Array(vec![Value::Integer(1), Value::Float(256.652)]);
582
583        let bytes = to_bytes(&original).unwrap();
584
585        let new: Value = from_bytes(&bytes).unwrap();
586
587        assert_eq!(original, new);
588    }
589
590    #[test]
591    fn hash() {
592        let mut hash = RbHash::new();
593        hash.insert(Value::Bool(true), Value::Integer(1));
594        hash.insert(Value::Symbol("a_symbol".into()), Value::Float(256.652));
595        let original = Value::Hash(hash);
596
597        let bytes = to_bytes(&original).unwrap();
598
599        let new: Value = from_bytes(&bytes).unwrap();
600
601        assert_eq!(original, new);
602    }
603
604    #[test]
605    fn userdata() {
606        let original = Value::Userdata(crate::Userdata {
607            class: "TestUserdata".into(),
608            data: vec![97, 98, 99, 100],
609        });
610
611        let bytes = to_bytes(&original).unwrap();
612
613        let new: Value = from_bytes(&bytes).unwrap();
614
615        assert_eq!(original, new);
616    }
617
618    #[test]
619    fn object() {
620        let mut fields = RbFields::new();
621        fields.insert("@field1".into(), Value::Bool(true));
622        fields.insert(
623            "@field2".into(),
624            Value::String("i've been round tripped".into()),
625        );
626        let original = Value::Object(crate::Object {
627            class: "Test".into(),
628            fields,
629        });
630
631        let bytes = to_bytes(&original).unwrap();
632
633        let new: Value = from_bytes(&bytes).unwrap();
634
635        assert_eq!(original, new);
636    }
637
638    #[test]
639    fn instance() {
640        let inner_value = Box::new(Value::String("I've been round tripped, with ivars!".into()));
641        let mut fields = RbFields::new();
642        fields.insert("E".into(), Value::Bool(true));
643        fields.insert("@round_trip".into(), Value::Integer(123));
644        let original = Value::Instance(Instance {
645            value: inner_value,
646            fields,
647        });
648
649        let bytes = to_bytes(&original).unwrap();
650
651        let new: Value = from_bytes(&bytes).unwrap();
652
653        assert_eq!(original, new);
654    }
655
656    #[test]
657    fn regex() {
658        let original = Value::Regex {
659            data: "/round trip/".into(),
660            flags: 0b1010,
661        };
662
663        let bytes = to_bytes(&original).unwrap();
664
665        let new: Value = from_bytes(&bytes).unwrap();
666
667        assert_eq!(original, new);
668    }
669
670    #[test]
671    fn rb_struct() {
672        let mut fields = RbFields::new();
673        fields.insert("field1".into(), Value::Bool(true));
674        fields.insert("field2".into(), Value::String("round trip".into()));
675        let original = Value::RbStruct(RbStruct {
676            class: "TestStruct".into(),
677            fields,
678        });
679
680        let bytes = to_bytes(&original).unwrap();
681
682        let new: Value = from_bytes(&bytes).unwrap();
683
684        assert_eq!(original, new);
685    }
686
687    #[test]
688    fn class() {
689        let original = Value::Class("TestClass".into());
690
691        let bytes = to_bytes(&original).unwrap();
692
693        let new: Value = from_bytes(&bytes).unwrap();
694
695        assert_eq!(original, new);
696    }
697
698    #[test]
699    fn module() {
700        let original = Value::Module("TestModule".into());
701
702        let bytes = to_bytes(&original).unwrap();
703
704        let new: Value = from_bytes(&bytes).unwrap();
705
706        assert_eq!(original, new);
707    }
708
709    #[test]
710    fn user_class() {
711        let inner_value = Box::new(Value::String("I'm a user class".into()));
712        let original = Value::UserClass {
713            class: "TestUserClass".into(),
714            value: inner_value,
715        };
716
717        let bytes = to_bytes(&original).unwrap();
718
719        let new: Value = from_bytes(&bytes).unwrap();
720
721        assert_eq!(original, new);
722    }
723
724    #[test]
725    fn user_marshal() {
726        let inner_value = Box::new(Value::String("I've been serialized as another type".into()));
727        let original = Value::UserMarshal {
728            class: "TestUserMarshal".into(),
729            value: inner_value,
730        };
731
732        let bytes = to_bytes(&original).unwrap();
733
734        let new: Value = from_bytes(&bytes).unwrap();
735
736        assert_eq!(original, new);
737    }
738
739    #[test]
740    fn data() {
741        let inner_value = Box::new(Value::String("???".into()));
742        let original = Value::Data {
743            class: "TestData".into(),
744            value: inner_value,
745        };
746
747        let bytes = to_bytes(&original).unwrap();
748
749        let new: Value = from_bytes(&bytes).unwrap();
750
751        assert_eq!(original, new);
752    }
753}