1use core::fmt;
6use core::marker::PhantomData;
7use core::mem::{ManuallyDrop, MaybeUninit};
8
9use crate::{
10    Chunk, Constrained, Decode, DecodeError, Decoder, Encode, EncodeError, Encoder, FromWire,
11    FromWireRef, IntoNatural, RawWireUnion, Slot, Unconstrained, Wire, munge,
12};
13
14#[repr(transparent)]
16pub struct WireResult<'de, T, E> {
17    raw: RawWireUnion,
18    _phantom: PhantomData<(&'de mut [Chunk], T, E)>,
19}
20
21impl<T, E> Drop for WireResult<'_, T, E> {
22    fn drop(&mut self) {
23        match self.raw.ordinal() {
24            ORD_OK => {
25                let _ = unsafe { self.raw.get().read_unchecked::<T>() };
26            }
27            ORD_ERR => {
28                let _ = unsafe { self.raw.get().read_unchecked::<E>() };
29            }
30            _ => unsafe { ::core::hint::unreachable_unchecked() },
31        }
32    }
33}
34
35unsafe impl<T: Wire, E: Wire> Wire for WireResult<'static, T, E> {
36    type Owned<'de> = WireResult<'de, T::Owned<'de>, E::Owned<'de>>;
37
38    #[inline]
39    fn zero_padding(out: &mut MaybeUninit<Self>) {
40        munge!(let Self { raw, _phantom: _ } = out);
41        RawWireUnion::zero_padding(raw);
42    }
43}
44
45impl<T: Constrained<Constraint = ()>, E: Constrained<Constraint = ()>> Unconstrained
46    for WireResult<'_, T, E>
47{
48}
49
50const ORD_OK: u64 = 1;
51const ORD_ERR: u64 = 2;
52
53impl<T, E> WireResult<'_, T, E> {
54    pub fn is_ok(&self) -> bool {
56        self.raw.ordinal() == ORD_OK
57    }
58
59    pub fn is_err(&self) -> bool {
61        self.raw.ordinal() == ORD_ERR
62    }
63
64    pub fn ok(&self) -> Option<&T> {
66        self.is_ok().then(|| unsafe { self.raw.get().deref_unchecked() })
67    }
68
69    pub fn err(&self) -> Option<&E> {
71        self.is_err().then(|| unsafe { self.raw.get().deref_unchecked() })
72    }
73
74    pub fn unwrap(&self) -> &T {
78        self.ok().unwrap()
79    }
80
81    pub fn unwrap_err(&self) -> &E {
85        self.err().unwrap()
86    }
87
88    pub fn as_ref(&self) -> Result<&T, &E> {
90        match self.raw.ordinal() {
91            ORD_OK => unsafe { Ok(self.raw.get().deref_unchecked()) },
92            ORD_ERR => unsafe { Err(self.raw.get().deref_unchecked()) },
93            _ => unsafe { ::core::hint::unreachable_unchecked() },
94        }
95    }
96
97    pub fn into_result(self) -> Result<T, E> {
99        let this = ManuallyDrop::new(self);
100        match this.raw.ordinal() {
101            ORD_OK => unsafe { Ok(this.raw.get().read_unchecked()) },
102            ORD_ERR => unsafe { Err(this.raw.get().read_unchecked()) },
103            _ => unsafe { ::core::hint::unreachable_unchecked() },
104        }
105    }
106}
107
108impl<T: Clone, E: Clone> Clone for WireResult<'_, T, E> {
109    fn clone(&self) -> Self {
110        Self {
111            raw: match self.raw.ordinal() {
112                ORD_OK => unsafe { self.raw.clone_inline_unchecked::<T>() },
113                ORD_ERR => unsafe { self.raw.clone_inline_unchecked::<E>() },
114                _ => unsafe { ::core::hint::unreachable_unchecked() },
115            },
116            _phantom: PhantomData,
117        }
118    }
119}
120
121impl<T, E> fmt::Debug for WireResult<'_, T, E>
122where
123    T: fmt::Debug,
124    E: fmt::Debug,
125{
126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127        self.as_ref().fmt(f)
128    }
129}
130
131unsafe impl<D, T, E> Decode<D> for WireResult<'static, T, E>
132where
133    D: Decoder + ?Sized,
134    T: Decode<D> + Constrained<Constraint = ()>,
135    E: Decode<D> + Constrained<Constraint = ()>,
136{
137    fn decode(slot: Slot<'_, Self>, decoder: &mut D, _: ()) -> Result<(), DecodeError> {
138        munge!(let Self { mut raw, _phantom: _ } = slot);
139
140        match RawWireUnion::encoded_ordinal(raw.as_mut()) {
141            ORD_OK => RawWireUnion::decode_as::<D, T>(raw, decoder, ())?,
142            ORD_ERR => RawWireUnion::decode_as::<D, E>(raw, decoder, ())?,
143            ord => return Err(DecodeError::InvalidUnionOrdinal(ord as usize)),
144        }
145
146        Ok(())
147    }
148}
149
150unsafe impl<Enc, WT, T, WE, E> Encode<WireResult<'static, WT, WE>, Enc> for Result<T, E>
151where
152    Enc: Encoder + ?Sized,
153    WT: Constrained<Constraint = ()> + Wire,
154    T: Encode<WT, Enc>,
155    WE: Constrained<Constraint = ()> + Wire,
156    E: Encode<WE, Enc>,
157{
158    fn encode(
159        self,
160        encoder: &mut Enc,
161        out: &mut MaybeUninit<WireResult<'static, WT, WE>>,
162        _: (),
163    ) -> Result<(), EncodeError> {
164        munge!(let WireResult { raw, _phantom: _ } = out);
165
166        match self {
167            Ok(value) => RawWireUnion::encode_as::<Enc, WT>(value, ORD_OK, encoder, raw, ())?,
168            Err(error) => RawWireUnion::encode_as::<Enc, WE>(error, ORD_ERR, encoder, raw, ())?,
169        }
170
171        Ok(())
172    }
173}
174
175unsafe impl<'a, Enc, WT, T, WE, E> Encode<WireResult<'static, WT, WE>, Enc> for &'a Result<T, E>
176where
177    Enc: Encoder + ?Sized,
178    WT: Constrained<Constraint = ()> + Wire,
179    &'a T: Encode<WT, Enc>,
180    WE: Constrained<Constraint = ()> + Wire,
181    &'a E: Encode<WE, Enc>,
182{
183    fn encode(
184        self,
185        encoder: &mut Enc,
186        out: &mut MaybeUninit<WireResult<'static, WT, WE>>,
187        _: (),
188    ) -> Result<(), EncodeError> {
189        self.as_ref().encode(encoder, out, ())
190    }
191}
192
193impl<T, E, WT, WE> FromWire<WireResult<'_, WT, WE>> for Result<T, E>
194where
195    T: FromWire<WT>,
196    E: FromWire<WE>,
197{
198    #[inline]
199    fn from_wire(wire: WireResult<'_, WT, WE>) -> Self {
200        match wire.into_result() {
201            Ok(value) => Ok(T::from_wire(value)),
202            Err(error) => Err(E::from_wire(error)),
203        }
204    }
205}
206
207impl<T: IntoNatural, E: IntoNatural> IntoNatural for WireResult<'_, T, E> {
208    type Natural = Result<T::Natural, E::Natural>;
209}
210
211impl<T, E, WT, WE> FromWireRef<WireResult<'_, WT, WE>> for Result<T, E>
212where
213    T: FromWireRef<WT>,
214    E: FromWireRef<WE>,
215{
216    #[inline]
217    fn from_wire_ref(wire: &WireResult<'_, WT, WE>) -> Self {
218        match wire.as_ref() {
219            Ok(value) => Ok(T::from_wire_ref(value)),
220            Err(error) => Err(E::from_wire_ref(error)),
221        }
222    }
223}