rkyv/impls/core/
option.rs1use 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
18unsafe 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}