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
21pub mod path_to_error;
64
65pub(crate) mod tag;
66
67pub mod de;
69pub 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#[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
107pub 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, "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 #[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}