1use super::*;
6use core::cmp::Ordering;
7use core::marker::PhantomData;
8use core::mem::{self, MaybeUninit};
9
10#[repr(C, packed)]
32pub struct OptionULE<U>(bool, MaybeUninit<U>);
33
34impl<U: Copy> OptionULE<U> {
35 pub fn get(self) -> Option<U> {
37 if self.0 {
38 unsafe {
39 Some(self.1.assume_init())
41 }
42 } else {
43 None
44 }
45 }
46
47 pub fn new(opt: Option<U>) -> Self {
49 if let Some(inner) = opt {
50 Self(true, MaybeUninit::new(inner))
51 } else {
52 Self(false, MaybeUninit::zeroed())
53 }
54 }
55}
56
57impl<U: Copy + core::fmt::Debug> core::fmt::Debug for OptionULE<U> {
58 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
59 self.get().fmt(f)
60 }
61}
62
63unsafe impl<U: ULE> ULE for OptionULE<U> {
76 fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
77 let size = mem::size_of::<Self>();
78 if bytes.len() % size != 0 {
79 return Err(UleError::length::<Self>(bytes.len()));
80 }
81 for chunk in bytes.chunks(size) {
82 #[expect(clippy::indexing_slicing)] match chunk[0] {
84 0 => {
87 if !chunk[1..].iter().all(|x| *x == 0) {
88 return Err(UleError::parse::<Self>());
89 }
90 }
91 1 => U::validate_bytes(&chunk[1..])?,
92 _ => return Err(UleError::parse::<Self>()),
93 }
94 }
95 Ok(())
96 }
97}
98
99impl<T: AsULE> AsULE for Option<T> {
100 type ULE = OptionULE<T::ULE>;
101 fn to_unaligned(self) -> OptionULE<T::ULE> {
102 OptionULE::new(self.map(T::to_unaligned))
103 }
104
105 fn from_unaligned(other: OptionULE<T::ULE>) -> Self {
106 other.get().map(T::from_unaligned)
107 }
108}
109
110impl<U: Copy> Copy for OptionULE<U> {}
111
112impl<U: Copy> Clone for OptionULE<U> {
113 fn clone(&self) -> Self {
114 *self
115 }
116}
117
118impl<U: Copy + PartialEq> PartialEq for OptionULE<U> {
119 fn eq(&self, other: &Self) -> bool {
120 self.get().eq(&other.get())
121 }
122}
123
124impl<U: Copy + Eq> Eq for OptionULE<U> {}
125
126#[repr(C, packed)]
145pub struct OptionVarULE<U: VarULE + ?Sized>(PhantomData<U>, bool, [u8]);
146
147impl<U: VarULE + ?Sized> OptionVarULE<U> {
148 pub fn as_ref(&self) -> Option<&U> {
150 if self.1 {
151 unsafe {
152 Some(U::from_bytes_unchecked(&self.2))
154 }
155 } else {
156 None
157 }
158 }
159}
160
161impl<U: VarULE + ?Sized + core::fmt::Debug> core::fmt::Debug for OptionVarULE<U> {
162 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
163 self.as_ref().fmt(f)
164 }
165}
166
167unsafe impl<U: VarULE + ?Sized> VarULE for OptionVarULE<U> {
177 #[inline]
178 fn validate_bytes(slice: &[u8]) -> Result<(), UleError> {
179 if slice.is_empty() {
180 return Err(UleError::length::<Self>(slice.len()));
181 }
182 #[expect(clippy::indexing_slicing)] match slice[0] {
184 0 => {
187 if slice.len() != 1 {
188 Err(UleError::length::<Self>(slice.len()))
189 } else {
190 Ok(())
191 }
192 }
193 1 => U::validate_bytes(&slice[1..]),
194 _ => Err(UleError::parse::<Self>()),
195 }
196 }
197
198 #[inline]
199 unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
200 let entire_struct_as_slice: *const [u8] =
201 ::core::ptr::slice_from_raw_parts(bytes.as_ptr(), bytes.len() - 1);
202 &*(entire_struct_as_slice as *const Self)
203 }
204}
205
206unsafe impl<T, U> EncodeAsVarULE<OptionVarULE<U>> for Option<T>
207where
208 T: EncodeAsVarULE<U>,
209 U: VarULE + ?Sized,
210{
211 fn encode_var_ule_as_slices<R>(&self, _: impl FnOnce(&[&[u8]]) -> R) -> R {
212 ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
214 }
215
216 #[inline]
217 fn encode_var_ule_len(&self) -> usize {
218 if let Some(ref inner) = *self {
219 1 + inner.encode_var_ule_len()
221 } else {
222 1
224 }
225 }
226
227 #[expect(clippy::indexing_slicing)] fn encode_var_ule_write(&self, dst: &mut [u8]) {
229 if let Some(ref inner) = *self {
230 if true {
if !!dst.is_empty() {
{
::core::panicking::panic_fmt(format_args!("OptionVarULE must have at least one byte when Some"));
}
};
};debug_assert!(
231 !dst.is_empty(),
232 "OptionVarULE must have at least one byte when Some"
233 );
234 dst[0] = 1;
235 inner.encode_var_ule_write(&mut dst[1..]);
236 } else {
237 if true {
if !(dst.len() == 1) {
{
::core::panicking::panic_fmt(format_args!("OptionVarULE must have exactly one byte when None"));
}
};
};debug_assert!(
238 dst.len() == 1,
239 "OptionVarULE must have exactly one byte when None"
240 );
241 dst[0] = 0;
242 }
243 }
244}
245
246impl<U: VarULE + ?Sized + PartialEq> PartialEq for OptionVarULE<U> {
247 fn eq(&self, other: &Self) -> bool {
248 self.as_ref().eq(&other.as_ref())
249 }
250}
251
252impl<U: VarULE + ?Sized + Eq> Eq for OptionVarULE<U> {}
253
254impl<U: VarULE + ?Sized + PartialOrd> PartialOrd for OptionVarULE<U> {
255 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
256 self.as_ref().partial_cmp(&other.as_ref())
257 }
258}
259
260impl<U: VarULE + ?Sized + Ord> Ord for OptionVarULE<U> {
261 fn cmp(&self, other: &Self) -> Ordering {
262 self.as_ref().cmp(&other.as_ref())
263 }
264}