rkyv/impls/core/
option.rs

1use core::hint::unreachable_unchecked;
2
3use munge::munge;
4use rancor::Fallible;
5
6use crate::{
7    option::ArchivedOption, traits::NoUndef, Archive, Deserialize, Place,
8    Serialize,
9};
10
11#[allow(dead_code)]
12#[repr(u8)]
13enum ArchivedOptionTag {
14    None,
15    Some,
16}
17
18// SAFETY: `ArchivedOptionTag` is `repr(u8)` and so always consists of a single
19// well-defined byte.
20unsafe impl NoUndef for ArchivedOptionTag {}
21
22#[repr(C)]
23struct ArchivedOptionVariantNone(ArchivedOptionTag);
24
25#[repr(C)]
26struct ArchivedOptionVariantSome<T>(ArchivedOptionTag, T);
27
28impl<T: Archive> Archive for Option<T> {
29    type Archived = ArchivedOption<T::Archived>;
30    type Resolver = Option<T::Resolver>;
31
32    fn resolve(&self, resolver: Self::Resolver, out: Place<Self::Archived>) {
33        match resolver {
34            None => {
35                let out = unsafe {
36                    out.cast_unchecked::<ArchivedOptionVariantNone>()
37                };
38                munge!(let ArchivedOptionVariantNone(tag) = out);
39                tag.write(ArchivedOptionTag::None);
40            }
41            Some(resolver) => {
42                let out = unsafe {
43                    out
44                    .cast_unchecked::<ArchivedOptionVariantSome<T::Archived>>()
45                };
46                munge!(let ArchivedOptionVariantSome(tag, out_value) = out);
47                tag.write(ArchivedOptionTag::Some);
48
49                let value = if let Some(value) = self.as_ref() {
50                    value
51                } else {
52                    unsafe {
53                        unreachable_unchecked();
54                    }
55                };
56
57                value.resolve(resolver, out_value);
58            }
59        }
60    }
61}
62
63impl<T: Serialize<S>, S: Fallible + ?Sized> Serialize<S> for Option<T> {
64    fn serialize(
65        &self,
66        serializer: &mut S,
67    ) -> Result<Self::Resolver, S::Error> {
68        self.as_ref()
69            .map(|value| value.serialize(serializer))
70            .transpose()
71    }
72}
73
74impl<T, D> Deserialize<Option<T>, D> for ArchivedOption<T::Archived>
75where
76    T: Archive,
77    T::Archived: Deserialize<T, D>,
78    D: Fallible + ?Sized,
79{
80    fn deserialize(&self, deserializer: &mut D) -> Result<Option<T>, D::Error> {
81        Ok(match self {
82            ArchivedOption::Some(value) => {
83                Some(value.deserialize(deserializer)?)
84            }
85            ArchivedOption::None => None,
86        })
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use crate::api::test::roundtrip;
93
94    #[test]
95    fn roundtrip_option() {
96        roundtrip(&Option::<()>::None);
97        roundtrip(&Some(42));
98    }
99}