1use core::{
4 cmp, fmt, hash, hint::unreachable_unchecked, mem::ManuallyDrop, ops::Deref,
5};
6
7use munge::munge;
8use rancor::Fallible;
9
10use crate::{
11 boxed::{ArchivedBox, BoxResolver},
12 seal::Seal,
13 ser::Writer,
14 traits::ArchivePointee,
15 ArchiveUnsized, Place, Portable, RelPtr, SerializeUnsized,
16};
17
18#[derive(Portable)]
22#[rkyv(crate)]
23#[cfg_attr(feature = "bytecheck", derive(bytecheck::CheckBytes))]
24#[repr(transparent)]
25pub struct ArchivedOptionBox<T: ArchivePointee + ?Sized> {
26 repr: Repr<T>,
27}
28
29#[derive(Portable)]
30#[rkyv(crate)]
31#[repr(C)]
32union Repr<T: ArchivePointee + ?Sized> {
33 boxed: ManuallyDrop<ArchivedBox<T>>,
34 ptr: ManuallyDrop<RelPtr<T>>,
35}
36
37impl<T: ArchivePointee + ?Sized> Repr<T> {
38 fn is_invalid(&self) -> bool {
39 unsafe { self.ptr.is_invalid() }
40 }
41}
42
43#[cfg(feature = "bytecheck")]
44const _: () = {
45 use crate::{
46 bytecheck::{CheckBytes, Verify},
47 rancor::Source,
48 traits::LayoutRaw,
49 validation::ArchiveContext,
50 };
51
52 unsafe impl<T, C> CheckBytes<C> for Repr<T>
53 where
54 T: ArchivePointee + ?Sized,
55 C: Fallible + ?Sized,
56 RelPtr<T>: CheckBytes<C>,
57 Self: Verify<C>,
58 {
59 unsafe fn check_bytes(
60 value: *const Self,
61 context: &mut C,
62 ) -> Result<(), C::Error> {
63 unsafe {
67 RelPtr::check_bytes(value.cast::<RelPtr<T>>(), context)?;
68 }
69
70 Self::verify(unsafe { &*value }, context)
72 }
73 }
74
75 unsafe impl<T, C> Verify<C> for Repr<T>
76 where
77 T: ArchivePointee + CheckBytes<C> + LayoutRaw + ?Sized,
78 T::ArchivedMetadata: CheckBytes<C>,
79 C: Fallible + ArchiveContext + ?Sized,
80 C::Error: Source,
81 {
82 fn verify(&self, context: &mut C) -> Result<(), C::Error> {
83 let is_invalid = unsafe { self.ptr.is_invalid() };
84 if is_invalid {
85 Ok(())
87 } else {
88 unsafe { self.boxed.verify(context) }
89 }
90 }
91 }
92};
93
94impl<T: ArchivePointee + ?Sized> ArchivedOptionBox<T> {
95 pub fn is_none(&self) -> bool {
97 self.as_ref().is_none()
98 }
99
100 pub fn is_some(&self) -> bool {
102 self.as_ref().is_some()
103 }
104
105 pub fn as_ref(&self) -> Option<&ArchivedBox<T>> {
107 if self.repr.is_invalid() {
108 None
109 } else {
110 unsafe { Some(&self.repr.boxed) }
111 }
112 }
113
114 pub fn as_mut(&mut self) -> Option<&mut ArchivedBox<T>> {
116 if self.repr.is_invalid() {
117 None
118 } else {
119 unsafe { Some(&mut self.repr.boxed) }
120 }
121 }
122
123 pub fn as_seal(this: Seal<'_, Self>) -> Option<Seal<'_, ArchivedBox<T>>> {
126 let this = unsafe { Seal::unseal_unchecked(this) };
127 this.as_mut().map(Seal::new)
128 }
129
130 pub fn iter(&self) -> Iter<&'_ ArchivedBox<T>> {
132 Iter::new(self.as_ref())
133 }
134
135 pub fn iter_mut(&mut self) -> Iter<&'_ mut ArchivedBox<T>> {
137 Iter::new(self.as_mut())
138 }
139
140 pub fn iter_seal(this: Seal<'_, Self>) -> Iter<Seal<'_, ArchivedBox<T>>> {
142 Iter::new(Self::as_seal(this))
143 }
144
145 pub fn as_deref(&self) -> Option<&T> {
150 self.as_ref().map(|x| (*x).deref())
151 }
152}
153
154impl<T: ArchivePointee + ?Sized> ArchivedOptionBox<T> {
155 pub fn resolve_from_option<U: ArchiveUnsized<Archived = T> + ?Sized>(
157 field: Option<&U>,
158 resolver: OptionBoxResolver,
159 out: Place<Self>,
160 ) {
161 munge!(let Self { repr } = out);
162 if let Some(value) = field {
163 let resolver =
164 if let OptionBoxResolver::Some(metadata_resolver) = resolver {
165 metadata_resolver
166 } else {
167 unsafe {
168 unreachable_unchecked();
169 }
170 };
171
172 let out = unsafe { repr.cast_unchecked::<ArchivedBox<T>>() };
173 ArchivedBox::resolve_from_ref(value, resolver, out)
174 } else {
175 let out = unsafe { repr.cast_unchecked::<RelPtr<T>>() };
176 RelPtr::emplace_invalid(out);
177 }
178 }
179
180 pub fn serialize_from_option<U, S>(
182 field: Option<&U>,
183 serializer: &mut S,
184 ) -> Result<OptionBoxResolver, S::Error>
185 where
186 U: SerializeUnsized<S, Archived = T> + ?Sized,
187 S: Fallible + Writer + ?Sized,
188 {
189 if let Some(value) = field {
190 Ok(OptionBoxResolver::Some(ArchivedBox::serialize_from_ref(
191 value, serializer,
192 )?))
193 } else {
194 Ok(OptionBoxResolver::None)
195 }
196 }
197}
198
199impl<T: ArchivePointee + ?Sized> fmt::Debug for ArchivedOptionBox<T>
200where
201 T::ArchivedMetadata: fmt::Debug,
202{
203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204 match self.as_ref() {
205 Some(inner) => inner.fmt(f),
206 None => f.debug_tuple("None").finish(),
207 }
208 }
209}
210
211impl<T: ArchivePointee + Eq + ?Sized> Eq for ArchivedOptionBox<T> {}
212
213impl<T: ArchivePointee + hash::Hash + ?Sized> hash::Hash
214 for ArchivedOptionBox<T>
215{
216 fn hash<H: hash::Hasher>(&self, state: &mut H) {
217 self.as_ref().hash(state)
218 }
219}
220
221impl<T: ArchivePointee + Ord + ?Sized> Ord for ArchivedOptionBox<T> {
222 fn cmp(&self, other: &Self) -> cmp::Ordering {
223 self.as_ref().cmp(&other.as_ref())
224 }
225}
226
227impl<T: ArchivePointee + PartialEq + ?Sized> PartialEq
228 for ArchivedOptionBox<T>
229{
230 fn eq(&self, other: &Self) -> bool {
231 self.as_ref().eq(&other.as_ref())
232 }
233}
234
235impl<T: ArchivePointee + PartialOrd + ?Sized> PartialOrd
236 for ArchivedOptionBox<T>
237{
238 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
239 self.as_ref().partial_cmp(&other.as_ref())
240 }
241}
242
243pub type Iter<P> = crate::option::Iter<P>;
249
250pub enum OptionBoxResolver {
252 None,
254 Some(BoxResolver),
256}