Skip to main content

rkyv/impls/alloc/
with.rs

1use core::{marker::PhantomData, ops::ControlFlow};
2
3use ptr_meta::Pointee;
4use rancor::{Fallible, Source};
5
6use crate::{
7    alloc::{
8        borrow::Cow,
9        boxed::Box,
10        collections::{BTreeMap, BTreeSet},
11        rc::Rc,
12        vec::Vec,
13    },
14    collections::{
15        btree_map::{ArchivedBTreeMap, BTreeMapResolver},
16        util::{Entry, EntryAdapter},
17    },
18    impls::core::with::RefWrapper,
19    niche::option_box::{ArchivedOptionBox, OptionBoxResolver},
20    ser::{Allocator, Writer},
21    string::{ArchivedString, StringResolver},
22    traits::LayoutRaw,
23    vec::{ArchivedVec, VecResolver},
24    with::{
25        ArchiveWith, AsOwned, AsVec, DeserializeWith, Map, MapKV, Niche,
26        SerializeWith, Unshare,
27    },
28    Archive, ArchiveUnsized, ArchivedMetadata, Deserialize, DeserializeUnsized,
29    Place, Serialize, SerializeUnsized,
30};
31
32// Implementation for `MapKV`
33
34impl<A, B, K, V> ArchiveWith<BTreeMap<K, V>> for MapKV<A, B>
35where
36    A: ArchiveWith<K>,
37    B: ArchiveWith<V>,
38{
39    type Archived = ArchivedBTreeMap<
40        <A as ArchiveWith<K>>::Archived,
41        <B as ArchiveWith<V>>::Archived,
42    >;
43    type Resolver = BTreeMapResolver;
44
45    fn resolve_with(
46        field: &BTreeMap<K, V>,
47        resolver: Self::Resolver,
48        out: Place<Self::Archived>,
49    ) {
50        ArchivedBTreeMap::resolve_from_len(field.len(), resolver, out)
51    }
52}
53
54impl<A, B, K, V, S> SerializeWith<BTreeMap<K, V>, S> for MapKV<A, B>
55where
56    A: ArchiveWith<K> + SerializeWith<K, S>,
57    B: ArchiveWith<V> + SerializeWith<V, S>,
58    <A as ArchiveWith<K>>::Archived: Ord,
59    S: Fallible + Allocator + Writer + ?Sized,
60    S::Error: Source,
61{
62    fn serialize_with(
63        field: &BTreeMap<K, V>,
64        serializer: &mut S,
65    ) -> Result<Self::Resolver, <S as Fallible>::Error> {
66        ArchivedBTreeMap::<_, _, 5>::serialize_from_ordered_iter(
67            field.iter().map(|(k, v)| {
68                (
69                    RefWrapper::<'_, A, K>(k, PhantomData::<A>),
70                    RefWrapper::<'_, B, V>(v, PhantomData::<B>),
71                )
72            }),
73            serializer,
74        )
75    }
76}
77
78impl<A, B, K, V, D>
79    DeserializeWith<
80        ArchivedBTreeMap<
81            <A as ArchiveWith<K>>::Archived,
82            <B as ArchiveWith<V>>::Archived,
83        >,
84        BTreeMap<K, V>,
85        D,
86    > for MapKV<A, B>
87where
88    A: ArchiveWith<K> + DeserializeWith<<A as ArchiveWith<K>>::Archived, K, D>,
89    B: ArchiveWith<V> + DeserializeWith<<B as ArchiveWith<V>>::Archived, V, D>,
90    K: Ord,
91    D: Fallible + ?Sized,
92{
93    fn deserialize_with(
94        field: &ArchivedBTreeMap<
95            <A as ArchiveWith<K>>::Archived,
96            <B as ArchiveWith<V>>::Archived,
97        >,
98        deserializer: &mut D,
99    ) -> Result<BTreeMap<K, V>, <D as Fallible>::Error> {
100        let mut result = BTreeMap::new();
101        let r = field.visit(|ak, av| {
102            let k = match A::deserialize_with(ak, deserializer) {
103                Ok(k) => k,
104                Err(e) => return ControlFlow::Break(e),
105            };
106            let v = match B::deserialize_with(av, deserializer) {
107                Ok(v) => v,
108                Err(e) => return ControlFlow::Break(e),
109            };
110            result.insert(k, v);
111            ControlFlow::Continue(())
112        });
113        match r {
114            Some(e) => Err(e),
115            None => Ok(result),
116        }
117    }
118}
119
120// Implementations for `Map`
121impl<A, O> ArchiveWith<Vec<O>> for Map<A>
122where
123    A: ArchiveWith<O>,
124{
125    type Archived = ArchivedVec<<A as ArchiveWith<O>>::Archived>;
126    type Resolver = VecResolver;
127
128    fn resolve_with(
129        field: &Vec<O>,
130        resolver: Self::Resolver,
131        out: Place<Self::Archived>,
132    ) {
133        ArchivedVec::resolve_from_len(field.len(), resolver, out)
134    }
135}
136
137impl<A, O, S> SerializeWith<Vec<O>, S> for Map<A>
138where
139    S: Fallible + Allocator + Writer + ?Sized,
140    A: ArchiveWith<O> + SerializeWith<O, S>,
141{
142    fn serialize_with(
143        field: &Vec<O>,
144        s: &mut S,
145    ) -> Result<Self::Resolver, S::Error> {
146        // Wrapper for O so that we have an Archive and Serialize implementation
147        // and ArchivedVec::serialize_from_* is happy about the bound
148        // constraints
149        struct RefWrapper<'o, A, O>(&'o O, PhantomData<A>);
150
151        impl<A: ArchiveWith<O>, O> Archive for RefWrapper<'_, A, O> {
152            type Archived = <A as ArchiveWith<O>>::Archived;
153            type Resolver = <A as ArchiveWith<O>>::Resolver;
154
155            fn resolve(
156                &self,
157                resolver: Self::Resolver,
158                out: Place<Self::Archived>,
159            ) {
160                A::resolve_with(self.0, resolver, out)
161            }
162        }
163
164        impl<A, O, S> Serialize<S> for RefWrapper<'_, A, O>
165        where
166            A: ArchiveWith<O> + SerializeWith<O, S>,
167            S: Fallible + Writer + ?Sized,
168        {
169            fn serialize(&self, s: &mut S) -> Result<Self::Resolver, S::Error> {
170                A::serialize_with(self.0, s)
171            }
172        }
173
174        let iter = field
175            .iter()
176            .map(|value| RefWrapper::<'_, A, O>(value, PhantomData));
177
178        ArchivedVec::serialize_from_iter(iter, s)
179    }
180}
181
182impl<A, O, D>
183    DeserializeWith<ArchivedVec<<A as ArchiveWith<O>>::Archived>, Vec<O>, D>
184    for Map<A>
185where
186    A: ArchiveWith<O> + DeserializeWith<<A as ArchiveWith<O>>::Archived, O, D>,
187    D: Fallible + ?Sized,
188{
189    fn deserialize_with(
190        field: &ArchivedVec<<A as ArchiveWith<O>>::Archived>,
191        d: &mut D,
192    ) -> Result<Vec<O>, D::Error> {
193        field
194            .iter()
195            .map(|value| A::deserialize_with(value, d))
196            .collect()
197    }
198}
199
200// AsOwned
201
202impl<'a, F: Archive + Clone> ArchiveWith<Cow<'a, F>> for AsOwned {
203    type Archived = F::Archived;
204    type Resolver = F::Resolver;
205
206    fn resolve_with(
207        field: &Cow<'a, F>,
208        resolver: Self::Resolver,
209        out: Place<Self::Archived>,
210    ) {
211        field.resolve(resolver, out);
212    }
213}
214
215impl<'a, F, S> SerializeWith<Cow<'a, F>, S> for AsOwned
216where
217    F: Serialize<S> + Clone,
218    S: Fallible + ?Sized,
219{
220    fn serialize_with(
221        field: &Cow<'a, F>,
222        serializer: &mut S,
223    ) -> Result<Self::Resolver, S::Error> {
224        field.serialize(serializer)
225    }
226}
227
228impl<T, D> DeserializeWith<T::Archived, T, D> for AsOwned
229where
230    T: Archive + Clone,
231    T::Archived: Deserialize<T, D>,
232    D: Fallible + ?Sized,
233{
234    fn deserialize_with(
235        field: &T::Archived,
236        deserializer: &mut D,
237    ) -> Result<T, D::Error> {
238        field.deserialize(deserializer)
239    }
240}
241
242impl<'a, T: Archive + Clone> ArchiveWith<Cow<'a, [T]>> for AsOwned {
243    type Archived = ArchivedVec<T::Archived>;
244    type Resolver = VecResolver;
245
246    fn resolve_with(
247        field: &Cow<'a, [T]>,
248        resolver: Self::Resolver,
249        out: Place<Self::Archived>,
250    ) {
251        ArchivedVec::resolve_from_slice(field, resolver, out);
252    }
253}
254
255impl<'a, T, S> SerializeWith<Cow<'a, [T]>, S> for AsOwned
256where
257    T: Serialize<S> + Clone,
258    S: Fallible + Allocator + Writer + ?Sized,
259{
260    fn serialize_with(
261        field: &Cow<'a, [T]>,
262        serializer: &mut S,
263    ) -> Result<Self::Resolver, S::Error> {
264        ArchivedVec::serialize_from_slice(field, serializer)
265    }
266}
267
268impl<'a, T, D> DeserializeWith<ArchivedVec<T::Archived>, Cow<'a, [T]>, D>
269    for AsOwned
270where
271    T: Archive + Clone,
272    T::Archived: Deserialize<T, D>,
273    D: Fallible + ?Sized,
274    D::Error: Source,
275{
276    fn deserialize_with(
277        field: &ArchivedVec<T::Archived>,
278        deserializer: &mut D,
279    ) -> Result<Cow<'a, [T]>, D::Error> {
280        Ok(Cow::Owned(field.deserialize(deserializer)?))
281    }
282}
283
284impl<'a> ArchiveWith<Cow<'a, str>> for AsOwned {
285    type Archived = ArchivedString;
286    type Resolver = StringResolver;
287
288    fn resolve_with(
289        field: &Cow<'a, str>,
290        resolver: Self::Resolver,
291        out: Place<Self::Archived>,
292    ) {
293        ArchivedString::resolve_from_str(field, resolver, out);
294    }
295}
296
297impl<'a, S> SerializeWith<Cow<'a, str>, S> for AsOwned
298where
299    S: Fallible + Writer + ?Sized,
300    S::Error: Source,
301{
302    fn serialize_with(
303        field: &Cow<'a, str>,
304        serializer: &mut S,
305    ) -> Result<Self::Resolver, S::Error> {
306        ArchivedString::serialize_from_str(field, serializer)
307    }
308}
309
310impl<'a, D> DeserializeWith<ArchivedString, Cow<'a, str>, D> for AsOwned
311where
312    D: Fallible + ?Sized,
313{
314    fn deserialize_with(
315        field: &ArchivedString,
316        deserializer: &mut D,
317    ) -> Result<Cow<'a, str>, D::Error> {
318        Ok(Cow::Owned(field.deserialize(deserializer)?))
319    }
320}
321
322// AsVec
323
324impl<K: Archive, V: Archive> ArchiveWith<BTreeMap<K, V>> for AsVec {
325    type Archived = ArchivedVec<Entry<K::Archived, V::Archived>>;
326    type Resolver = VecResolver;
327
328    fn resolve_with(
329        field: &BTreeMap<K, V>,
330        resolver: Self::Resolver,
331        out: Place<Self::Archived>,
332    ) {
333        ArchivedVec::resolve_from_len(field.len(), resolver, out);
334    }
335}
336
337impl<K, V, S> SerializeWith<BTreeMap<K, V>, S> for AsVec
338where
339    K: Serialize<S>,
340    V: Serialize<S>,
341    S: Fallible + Allocator + Writer + ?Sized,
342{
343    fn serialize_with(
344        field: &BTreeMap<K, V>,
345        serializer: &mut S,
346    ) -> Result<Self::Resolver, S::Error> {
347        ArchivedVec::serialize_from_iter(
348            field.iter().map(|(key, value)| {
349                EntryAdapter::<_, _, K, V>::new(key, value)
350            }),
351            serializer,
352        )
353    }
354}
355
356impl<K, V, D>
357    DeserializeWith<
358        ArchivedVec<Entry<K::Archived, V::Archived>>,
359        BTreeMap<K, V>,
360        D,
361    > for AsVec
362where
363    K: Archive + Ord,
364    V: Archive,
365    K::Archived: Deserialize<K, D>,
366    V::Archived: Deserialize<V, D>,
367    D: Fallible + ?Sized,
368{
369    fn deserialize_with(
370        field: &ArchivedVec<Entry<K::Archived, V::Archived>>,
371        deserializer: &mut D,
372    ) -> Result<BTreeMap<K, V>, D::Error> {
373        let mut result = BTreeMap::new();
374        for entry in field.iter() {
375            result.insert(
376                entry.key.deserialize(deserializer)?,
377                entry.value.deserialize(deserializer)?,
378            );
379        }
380        Ok(result)
381    }
382}
383
384impl<T: Archive> ArchiveWith<BTreeSet<T>> for AsVec {
385    type Archived = ArchivedVec<T::Archived>;
386    type Resolver = VecResolver;
387
388    fn resolve_with(
389        field: &BTreeSet<T>,
390        resolver: Self::Resolver,
391        out: Place<Self::Archived>,
392    ) {
393        ArchivedVec::resolve_from_len(field.len(), resolver, out);
394    }
395}
396
397impl<T, S> SerializeWith<BTreeSet<T>, S> for AsVec
398where
399    T: Serialize<S>,
400    S: Fallible + Allocator + Writer + ?Sized,
401{
402    fn serialize_with(
403        field: &BTreeSet<T>,
404        serializer: &mut S,
405    ) -> Result<Self::Resolver, S::Error> {
406        ArchivedVec::<T::Archived>::serialize_from_iter::<T, _, _>(
407            field.iter(),
408            serializer,
409        )
410    }
411}
412
413impl<T, D> DeserializeWith<ArchivedVec<T::Archived>, BTreeSet<T>, D> for AsVec
414where
415    T: Archive + Ord,
416    T::Archived: Deserialize<T, D>,
417    D: Fallible + ?Sized,
418{
419    fn deserialize_with(
420        field: &ArchivedVec<T::Archived>,
421        deserializer: &mut D,
422    ) -> Result<BTreeSet<T>, D::Error> {
423        let mut result = BTreeSet::new();
424        for key in field.iter() {
425            result.insert(key.deserialize(deserializer)?);
426        }
427        Ok(result)
428    }
429}
430
431// Niche
432
433impl<T> ArchiveWith<Option<Box<T>>> for Niche
434where
435    T: ArchiveUnsized + ?Sized,
436    ArchivedMetadata<T>: Default,
437{
438    type Archived = ArchivedOptionBox<T::Archived>;
439    type Resolver = OptionBoxResolver;
440
441    fn resolve_with(
442        field: &Option<Box<T>>,
443        resolver: Self::Resolver,
444        out: Place<Self::Archived>,
445    ) {
446        ArchivedOptionBox::resolve_from_option(field.as_deref(), resolver, out);
447    }
448}
449
450impl<T, S> SerializeWith<Option<Box<T>>, S> for Niche
451where
452    T: SerializeUnsized<S> + ?Sized,
453    S: Fallible + Writer + ?Sized,
454    ArchivedMetadata<T>: Default,
455{
456    fn serialize_with(
457        field: &Option<Box<T>>,
458        serializer: &mut S,
459    ) -> Result<Self::Resolver, S::Error> {
460        ArchivedOptionBox::serialize_from_option(field.as_deref(), serializer)
461    }
462}
463
464impl<T, D> DeserializeWith<ArchivedOptionBox<T::Archived>, Option<Box<T>>, D>
465    for Niche
466where
467    T: ArchiveUnsized + LayoutRaw + Pointee + ?Sized,
468    T::Archived: DeserializeUnsized<T, D>,
469    D: Fallible + ?Sized,
470    D::Error: Source,
471{
472    fn deserialize_with(
473        field: &ArchivedOptionBox<T::Archived>,
474        deserializer: &mut D,
475    ) -> Result<Option<Box<T>>, D::Error> {
476        if let Some(value) = field.as_ref() {
477            Ok(Some(value.deserialize(deserializer)?))
478        } else {
479            Ok(None)
480        }
481    }
482}
483
484// Unshare
485
486#[cfg(target_has_atomic = "ptr")]
487impl<T: Archive> ArchiveWith<crate::alloc::sync::Arc<T>> for Unshare {
488    type Archived = T::Archived;
489    type Resolver = T::Resolver;
490
491    fn resolve_with(
492        x: &crate::alloc::sync::Arc<T>,
493        resolver: Self::Resolver,
494        out: Place<Self::Archived>,
495    ) {
496        x.as_ref().resolve(resolver, out)
497    }
498}
499
500#[cfg(target_has_atomic = "ptr")]
501impl<T, S> SerializeWith<crate::alloc::sync::Arc<T>, S> for Unshare
502where
503    T: Serialize<S>,
504    S: Fallible + ?Sized,
505{
506    fn serialize_with(
507        x: &crate::alloc::sync::Arc<T>,
508        s: &mut S,
509    ) -> Result<Self::Resolver, S::Error> {
510        x.as_ref().serialize(s)
511    }
512}
513
514#[cfg(target_has_atomic = "ptr")]
515impl<A, T, D> DeserializeWith<A, crate::alloc::sync::Arc<T>, D> for Unshare
516where
517    A: Deserialize<T, D>,
518    D: Fallible + ?Sized,
519{
520    fn deserialize_with(
521        x: &A,
522        d: &mut D,
523    ) -> Result<crate::alloc::sync::Arc<T>, D::Error> {
524        Ok(crate::alloc::sync::Arc::new(A::deserialize(x, d)?))
525    }
526}
527
528impl<T: Archive> ArchiveWith<Rc<T>> for Unshare {
529    type Archived = T::Archived;
530    type Resolver = T::Resolver;
531
532    fn resolve_with(
533        x: &Rc<T>,
534        resolver: Self::Resolver,
535        out: Place<Self::Archived>,
536    ) {
537        x.as_ref().resolve(resolver, out)
538    }
539}
540
541impl<T: Serialize<S>, S: Fallible + ?Sized> SerializeWith<Rc<T>, S>
542    for Unshare
543{
544    fn serialize_with(
545        x: &Rc<T>,
546        s: &mut S,
547    ) -> Result<Self::Resolver, S::Error> {
548        x.as_ref().serialize(s)
549    }
550}
551
552impl<A, T, D> DeserializeWith<A, Rc<T>, D> for Unshare
553where
554    A: Deserialize<T, D>,
555    D: Fallible + ?Sized,
556{
557    fn deserialize_with(x: &A, d: &mut D) -> Result<Rc<T>, D::Error> {
558        Ok(Rc::new(A::deserialize(x, d)?))
559    }
560}
561
562#[cfg(test)]
563mod tests {
564    use core::mem::size_of;
565
566    use crate::{
567        alloc::{
568            borrow::Cow,
569            boxed::Box,
570            collections::{BTreeMap, BTreeSet},
571            string::{String, ToString},
572        },
573        api::test::{roundtrip, roundtrip_with, to_archived},
574        niche::niching::Null,
575        with::{
576            AsOwned, AsVec, DefaultNiche, InlineAsBox, Map, MapKV, Niche,
577            NicheInto,
578        },
579        Archive, Deserialize, Serialize,
580    };
581
582    #[derive(Debug, Archive, Deserialize, Serialize, PartialEq)]
583    #[rkyv(crate, compare(PartialEq), derive(Debug))]
584    struct Test {
585        value: Option<Box<u128>>,
586    }
587
588    #[test]
589    fn roundtrip_niche_none() {
590        roundtrip(&Test { value: None });
591    }
592
593    #[test]
594    fn roundtrip_niche_some() {
595        roundtrip(&Test {
596            value: Some(Box::new(128)),
597        });
598    }
599
600    #[test]
601    fn ambiguous_niched_archived_box() {
602        #[derive(Archive, Deserialize, Serialize, Debug, PartialEq)]
603        #[rkyv(crate, compare(PartialEq), derive(Debug))]
604        struct HasNiche {
605            #[rkyv(with = Niche)]
606            inner: Option<Box<[u32]>>,
607        }
608
609        roundtrip(&HasNiche {
610            inner: Some(Box::<[u32]>::from([])),
611        });
612        roundtrip(&HasNiche { inner: None });
613    }
614
615    #[test]
616    fn with_as_owned() {
617        #[derive(Archive, Serialize, Deserialize)]
618        #[rkyv(crate)]
619        struct Test<'a> {
620            #[rkyv(with = AsOwned)]
621            a: Cow<'a, u32>,
622            #[rkyv(with = AsOwned)]
623            b: Cow<'a, [u32]>,
624            #[rkyv(with = AsOwned)]
625            c: Cow<'a, str>,
626        }
627
628        let value = Test {
629            a: Cow::Borrowed(&100),
630            b: Cow::Borrowed(&[1, 2, 3, 4, 5, 6]),
631            c: Cow::Borrowed("hello world"),
632        };
633        to_archived(&value, |archived| {
634            assert_eq!(archived.a, 100);
635            assert_eq!(archived.b, [1, 2, 3, 4, 5, 6]);
636            assert_eq!(archived.c, "hello world");
637        });
638    }
639
640    #[test]
641    fn with_as_map() {
642        #[derive(Archive, Serialize, Deserialize)]
643        #[rkyv(crate)]
644        struct Test<'a> {
645            #[rkyv(with = Map<InlineAsBox>)]
646            a: Option<&'a str>,
647            #[rkyv(with = Map<InlineAsBox>)]
648            b: Option<&'a str>,
649        }
650
651        let value = Test {
652            a: Some("foo"),
653            b: None,
654        };
655
656        to_archived(&value, |archived| {
657            assert!(archived.a.is_some());
658            assert!(archived.b.is_none());
659        });
660    }
661
662    #[test]
663    fn with_as_mapkv() {
664        #[derive(Archive, Serialize, Deserialize)]
665        #[rkyv(crate)]
666        struct Test<'a> {
667            #[rkyv(with = MapKV<InlineAsBox, InlineAsBox>)]
668            a: BTreeMap<&'a str, &'a str>,
669        }
670
671        let mut a = BTreeMap::new();
672        a.insert("foo", "bar");
673        a.insert("woo", "roo");
674
675        let value = Test { a };
676
677        to_archived(&value, |archived| {
678            assert_eq!(archived.a.len(), 2);
679            assert!(archived.a.contains_key("foo"));
680            assert_eq!(**archived.a.get("woo").unwrap(), *"roo");
681        });
682    }
683
684    #[test]
685    fn with_as_vec() {
686        #[derive(Archive, Serialize, Deserialize)]
687        #[rkyv(crate)]
688        struct Test {
689            #[rkyv(with = AsVec)]
690            a: BTreeMap<String, String>,
691            #[rkyv(with = AsVec)]
692            b: BTreeSet<String>,
693            #[rkyv(with = AsVec)]
694            c: BTreeMap<String, String>,
695        }
696
697        let mut a = BTreeMap::new();
698        a.insert("foo".to_string(), "hello".to_string());
699        a.insert("bar".to_string(), "world".to_string());
700        a.insert("baz".to_string(), "bat".to_string());
701
702        let mut b = BTreeSet::new();
703        b.insert("foo".to_string());
704        b.insert("hello world!".to_string());
705        b.insert("bar".to_string());
706        b.insert("fizzbuzz".to_string());
707
708        let c = BTreeMap::new();
709
710        let value = Test { a, b, c };
711
712        to_archived(&value, |archived| {
713            assert_eq!(archived.a.len(), 3);
714            assert!(archived
715                .a
716                .iter()
717                .find(|&e| e.key == "foo" && e.value == "hello")
718                .is_some());
719            assert!(archived
720                .a
721                .iter()
722                .find(|&e| e.key == "bar" && e.value == "world")
723                .is_some());
724            assert!(archived
725                .a
726                .iter()
727                .find(|&e| e.key == "baz" && e.value == "bat")
728                .is_some());
729
730            assert_eq!(archived.b.len(), 4);
731            assert!(archived.b.iter().find(|&e| e == "foo").is_some());
732            assert!(archived.b.iter().find(|&e| e == "hello world!").is_some());
733            assert!(archived.b.iter().find(|&e| e == "bar").is_some());
734            assert!(archived.b.iter().find(|&e| e == "fizzbuzz").is_some());
735        });
736    }
737
738    #[cfg(feature = "alloc")]
739    #[test]
740    fn with_niche_box() {
741        #[derive(Archive, Serialize, Deserialize)]
742        #[rkyv(crate)]
743        struct TestNiche {
744            #[rkyv(with = Niche)]
745            inner: Option<Box<String>>,
746        }
747
748        #[derive(Archive, Serialize, Deserialize)]
749        #[rkyv(crate)]
750        struct TestNullNiche {
751            #[rkyv(with = NicheInto<Null>)]
752            inner: Option<Box<String>>,
753        }
754
755        #[derive(Archive, Serialize, Deserialize)]
756        #[rkyv(crate)]
757        struct TestNoNiching {
758            inner: Option<Box<String>>,
759        }
760
761        let value = TestNiche {
762            inner: Some(Box::new("hello world".to_string())),
763        };
764        to_archived(&value, |archived| {
765            assert!(archived.inner.is_some());
766            assert_eq!(&**archived.inner.as_ref().unwrap(), "hello world");
767            assert_eq!(archived.inner, value.inner);
768        });
769
770        let value = TestNiche { inner: None };
771        to_archived(&value, |archived| {
772            assert!(archived.inner.is_none());
773            assert_eq!(archived.inner, value.inner);
774        });
775        assert!(
776            size_of::<ArchivedTestNiche>() < size_of::<ArchivedTestNoNiching>()
777        );
778
779        let value = TestNullNiche {
780            inner: Some(Box::new("hello world".to_string())),
781        };
782        to_archived(&value, |archived| {
783            assert!(archived.inner.is_some());
784            assert_eq!(&**archived.inner.as_ref().unwrap(), "hello world");
785            assert_eq!(archived.inner, value.inner);
786        });
787
788        let value = TestNullNiche { inner: None };
789        to_archived(&value, |archived| {
790            assert!(archived.inner.is_none());
791            assert_eq!(archived.inner, value.inner);
792        });
793        assert!(
794            size_of::<ArchivedTestNullNiche>()
795                < size_of::<ArchivedTestNoNiching>()
796        );
797    }
798
799    #[test]
800    fn with_null_niching() {
801        #[derive(Archive, Serialize, Deserialize, Debug, PartialEq)]
802        #[rkyv(crate, derive(Debug))]
803        struct Nichable {
804            #[rkyv(niche)] // Default = Null
805            boxed: Box<i32>,
806        }
807
808        #[derive(Archive, Serialize, Deserialize, Debug, PartialEq)]
809        #[rkyv(crate, derive(Debug))]
810        struct Outer {
811            #[rkyv(with = DefaultNiche)]
812            field: Option<Nichable>,
813        }
814
815        assert_eq!(size_of::<ArchivedNichable>(), size_of::<ArchivedOuter>());
816
817        let values = [
818            Outer { field: None },
819            Outer {
820                field: Some(Nichable {
821                    boxed: Box::new(727),
822                }),
823            },
824        ];
825
826        roundtrip_with(&values[0], |_, archived| {
827            assert!(archived.field.is_none());
828        });
829        roundtrip_with(&values[1], |_, archived| {
830            let nichable = archived.field.as_ref().unwrap();
831            assert_eq!(nichable.boxed.as_ref().to_native(), 727);
832        });
833    }
834}