1use core::fmt;
6use core::mem::{MaybeUninit, forget};
7use core::ptr::NonNull;
8
9use munge::munge;
10
11use crate::{
12 Constrained, Decode, DecodeError, Decoder, DecoderExt as _, FromWire, FromWireOption,
13 FromWireOptionRef, FromWireRef, IntoNatural, Slot, ValidationError, Wire, wire,
14};
15
16#[repr(C)]
18pub struct Box<'de, T> {
19 ptr: wire::Pointer<'de, T>,
20}
21
22unsafe impl<T: Send> Send for Box<'_, T> {}
25
26unsafe impl<T: Sync> Sync for Box<'_, T> {}
28
29impl<T> Drop for Box<'_, T> {
30 fn drop(&mut self) {
31 if self.is_some() {
32 unsafe {
35 self.ptr.as_ptr().drop_in_place();
36 }
37 }
38 }
39}
40
41unsafe impl<T: Wire> Wire for Box<'static, T> {
43 type Narrowed<'de> = Box<'de, T::Narrowed<'de>>;
44
45 #[inline]
46 fn zero_padding(_: &mut MaybeUninit<Self>) {
47 }
49}
50
51impl<T> Box<'_, T> {
52 pub fn encode_present(out: &mut MaybeUninit<Self>) {
54 munge!(let Self { ptr } = out);
55 wire::Pointer::encode_present(ptr);
56 }
57
58 pub fn encode_absent(out: &mut MaybeUninit<Self>) {
60 munge!(let Self { ptr } = out);
61 wire::Pointer::encode_absent(ptr);
62 }
63
64 pub fn is_some(&self) -> bool {
66 !self.ptr.as_ptr().is_null()
67 }
68
69 pub fn is_none(&self) -> bool {
71 !self.is_some()
72 }
73
74 pub fn as_ref(&self) -> Option<&T> {
76 NonNull::new(self.ptr.as_ptr()).map(|ptr| unsafe { ptr.as_ref() })
78 }
79
80 pub fn into_option(self) -> Option<T> {
82 let ptr = self.ptr.as_ptr();
83 forget(self);
84 if ptr.is_null() {
85 None
86 } else {
87 unsafe { Some(ptr.read()) }
90 }
91 }
92}
93
94impl<T: fmt::Debug> fmt::Debug for Box<'_, T> {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 self.as_ref().fmt(f)
97 }
98}
99
100unsafe impl<'de, D: Decoder<'de> + ?Sized, T: Decode<D>> Decode<D> for Box<'de, T> {
102 fn decode(
103 slot: Slot<'_, Self>,
104 decoder: &mut D,
105 constraint: Self::Constraint,
106 ) -> Result<(), DecodeError> {
107 munge!(let Self { mut ptr } = slot);
108
109 if wire::Pointer::is_encoded_present(ptr.as_mut())? {
110 let mut value = decoder.take_slot::<T>()?;
111 T::decode(value.as_mut(), decoder, constraint)?;
112 wire::Pointer::set_decoded(ptr, value);
113 }
114
115 Ok(())
116 }
117}
118
119impl<T: FromWire<W>, W> FromWireOption<Box<'_, W>> for T {
120 fn from_wire_option(wire: Box<'_, W>) -> Option<Self> {
121 wire.into_option().map(T::from_wire)
122 }
123}
124
125impl<T: IntoNatural> IntoNatural for Box<'_, T> {
126 type Natural = Option<T::Natural>;
127}
128
129impl<T: FromWireRef<W>, W> FromWireOptionRef<Box<'_, W>> for T {
130 fn from_wire_option_ref(wire: &Box<'_, W>) -> Option<Self> {
131 wire.as_ref().map(T::from_wire_ref)
132 }
133}
134
135impl<T: Constrained> Constrained for Box<'_, T> {
136 type Constraint = T::Constraint;
137
138 fn validate(slot: Slot<'_, Self>, constraint: Self::Constraint) -> Result<(), ValidationError> {
139 munge!(let Self { ptr } = slot);
140
141 let ptr = unsafe { ptr.deref_unchecked() };
144 let ptr = ptr.as_ptr();
145 let member_slot = unsafe { Slot::new_unchecked(ptr) };
149 T::validate(member_slot, constraint)
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use crate::{DecoderExt as _, EncoderExt as _, chunks, wire};
156
157 #[test]
158 fn decode_box() {
159 assert_eq!(
160 chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
161 .as_mut_slice()
162 .decode::<wire::Box<'_, wire::Uint64>>()
163 .unwrap()
164 .as_ref(),
165 None,
166 );
167 assert_eq!(
168 chunks![
169 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56,
170 0x34, 0x12,
171 ]
172 .as_mut_slice()
173 .decode::<wire::Box<'_, wire::Uint64>>()
174 .unwrap()
175 .as_ref(),
176 Some(&wire::Uint64(0x123456789abcdef0u64)),
177 );
178 }
179
180 #[test]
181 fn encode_box() {
182 assert_eq!(
183 Vec::encode(None::<u64>).unwrap(),
184 chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
185 );
186 assert_eq!(
187 Vec::encode(Some(0x123456789abcdef0u64)).unwrap(),
188 chunks![
189 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56,
190 0x34, 0x12,
191 ],
192 );
193 }
194}