Skip to main content

facet_reflect/poke/
result.rs

1use core::mem::ManuallyDrop;
2
3use facet_core::{Facet, PtrUninit, ResultDef, ResultVTable};
4
5use crate::{HeapValue, ReflectError, ReflectErrorKind};
6
7use super::Poke;
8
9/// Lets you mutate a result (implements mutable result operations)
10pub struct PokeResult<'mem, 'facet> {
11    value: Poke<'mem, 'facet>,
12    def: ResultDef,
13}
14
15impl<'mem, 'facet> core::fmt::Debug for PokeResult<'mem, 'facet> {
16    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
17        f.debug_struct("PokeResult").finish_non_exhaustive()
18    }
19}
20
21impl<'mem, 'facet> PokeResult<'mem, 'facet> {
22    /// Creates a new poke result
23    ///
24    /// # Safety
25    ///
26    /// The caller must ensure that `def` contains valid vtable function pointers that
27    /// correctly implement the result operations for the actual type, and that the
28    /// ok/err types match `def.t()` / `def.e()`.
29    #[inline]
30    pub const unsafe fn new(value: Poke<'mem, 'facet>, def: ResultDef) -> Self {
31        Self { value, def }
32    }
33
34    fn err_reflect(&self, kind: ReflectErrorKind) -> ReflectError {
35        self.value.err(kind)
36    }
37
38    /// Returns the result definition
39    #[inline(always)]
40    pub const fn def(&self) -> ResultDef {
41        self.def
42    }
43
44    /// Returns the result vtable
45    #[inline(always)]
46    pub const fn vtable(&self) -> &'static ResultVTable {
47        self.def.vtable
48    }
49
50    /// Returns whether the result is Ok
51    #[inline]
52    pub fn is_ok(&self) -> bool {
53        unsafe { (self.vtable().is_ok)(self.value.data()) }
54    }
55
56    /// Returns whether the result is Err
57    #[inline]
58    pub fn is_err(&self) -> bool {
59        !self.is_ok()
60    }
61
62    /// Returns the Ok value as a read-only `Peek` if the result is Ok, `None` otherwise.
63    #[inline]
64    pub fn ok(&self) -> Option<crate::Peek<'_, 'facet>> {
65        unsafe {
66            let inner_data = (self.vtable().get_ok)(self.value.data());
67            if inner_data.is_null() {
68                None
69            } else {
70                Some(crate::Peek::unchecked_new(
71                    facet_core::PtrConst::new_sized(inner_data),
72                    self.def.t(),
73                ))
74            }
75        }
76    }
77
78    /// Returns the Err value as a read-only `Peek` if the result is Err, `None` otherwise.
79    #[inline]
80    pub fn err(&self) -> Option<crate::Peek<'_, 'facet>> {
81        unsafe {
82            let inner_data = (self.vtable().get_err)(self.value.data());
83            if inner_data.is_null() {
84                None
85            } else {
86                Some(crate::Peek::unchecked_new(
87                    facet_core::PtrConst::new_sized(inner_data),
88                    self.def.e(),
89                ))
90            }
91        }
92    }
93
94    /// Returns the Ok value as a mutable `Poke` if the result is Ok, `None` otherwise.
95    #[inline]
96    pub fn ok_mut(&mut self) -> Option<Poke<'_, 'facet>> {
97        unsafe {
98            let inner_data = (self.vtable().get_ok)(self.value.data());
99            if inner_data.is_null() {
100                return None;
101            }
102            let offset = inner_data.offset_from(self.value.data().as_byte_ptr()) as usize;
103            let inner_data = self.value.data_mut().field(offset);
104            Some(Poke::from_raw_parts(inner_data, self.def.t()))
105        }
106    }
107
108    /// Returns the Err value as a mutable `Poke` if the result is Err, `None` otherwise.
109    #[inline]
110    pub fn err_mut(&mut self) -> Option<Poke<'_, 'facet>> {
111        unsafe {
112            let inner_data = (self.vtable().get_err)(self.value.data());
113            if inner_data.is_null() {
114                return None;
115            }
116            let offset = inner_data.offset_from(self.value.data().as_byte_ptr()) as usize;
117            let inner_data = self.value.data_mut().field(offset);
118            Some(Poke::from_raw_parts(inner_data, self.def.e()))
119        }
120    }
121
122    /// Sets the result to `Ok(value)`, dropping the previous value.
123    pub fn set_ok<T: Facet<'facet>>(&mut self, value: T) -> Result<(), ReflectError> {
124        if self.def.t() != T::SHAPE {
125            return Err(self.err_reflect(ReflectErrorKind::WrongShape {
126                expected: self.def.t(),
127                actual: T::SHAPE,
128            }));
129        }
130
131        let mut value = ManuallyDrop::new(value);
132        unsafe {
133            // Drop the old value, then re-initialize in place.
134            self.value.shape.call_drop_in_place(self.value.data_mut());
135            let uninit = PtrUninit::new(self.value.data_mut().as_mut_byte_ptr());
136            let value_ptr = facet_core::PtrMut::new(&mut value as *mut ManuallyDrop<T> as *mut u8);
137            (self.vtable().init_ok)(uninit, value_ptr);
138        }
139        Ok(())
140    }
141
142    /// Sets the result to `Err(value)`, dropping the previous value.
143    pub fn set_err<E: Facet<'facet>>(&mut self, value: E) -> Result<(), ReflectError> {
144        if self.def.e() != E::SHAPE {
145            return Err(self.err_reflect(ReflectErrorKind::WrongShape {
146                expected: self.def.e(),
147                actual: E::SHAPE,
148            }));
149        }
150
151        let mut value = ManuallyDrop::new(value);
152        unsafe {
153            self.value.shape.call_drop_in_place(self.value.data_mut());
154            let uninit = PtrUninit::new(self.value.data_mut().as_mut_byte_ptr());
155            let value_ptr = facet_core::PtrMut::new(&mut value as *mut ManuallyDrop<E> as *mut u8);
156            (self.vtable().init_err)(uninit, value_ptr);
157        }
158        Ok(())
159    }
160
161    /// Type-erased [`set_ok`](Self::set_ok).
162    ///
163    /// Accepts a [`HeapValue`] whose shape must match the result's Ok type.
164    pub fn set_ok_from_heap<const BORROW: bool>(
165        &mut self,
166        value: HeapValue<'facet, BORROW>,
167    ) -> Result<(), ReflectError> {
168        if self.def.t() != value.shape() {
169            return Err(self.err_reflect(ReflectErrorKind::WrongShape {
170                expected: self.def.t(),
171                actual: value.shape(),
172            }));
173        }
174
175        let mut value = value;
176        let guard = value
177            .guard
178            .take()
179            .expect("HeapValue guard was already taken");
180        unsafe {
181            self.value.shape.call_drop_in_place(self.value.data_mut());
182            let uninit = PtrUninit::new(self.value.data_mut().as_mut_byte_ptr());
183            let value_ptr = facet_core::PtrMut::new(guard.ptr.as_ptr());
184            (self.vtable().init_ok)(uninit, value_ptr);
185        }
186        drop(guard);
187        Ok(())
188    }
189
190    /// Type-erased [`set_err`](Self::set_err).
191    ///
192    /// Accepts a [`HeapValue`] whose shape must match the result's Err type.
193    pub fn set_err_from_heap<const BORROW: bool>(
194        &mut self,
195        value: HeapValue<'facet, BORROW>,
196    ) -> Result<(), ReflectError> {
197        if self.def.e() != value.shape() {
198            return Err(self.err_reflect(ReflectErrorKind::WrongShape {
199                expected: self.def.e(),
200                actual: value.shape(),
201            }));
202        }
203
204        let mut value = value;
205        let guard = value
206            .guard
207            .take()
208            .expect("HeapValue guard was already taken");
209        unsafe {
210            self.value.shape.call_drop_in_place(self.value.data_mut());
211            let uninit = PtrUninit::new(self.value.data_mut().as_mut_byte_ptr());
212            let value_ptr = facet_core::PtrMut::new(guard.ptr.as_ptr());
213            (self.vtable().init_err)(uninit, value_ptr);
214        }
215        drop(guard);
216        Ok(())
217    }
218
219    /// Converts this `PokeResult` back into a `Poke`
220    #[inline]
221    pub const fn into_inner(self) -> Poke<'mem, 'facet> {
222        self.value
223    }
224
225    /// Returns a read-only `PeekResult` view
226    #[inline]
227    pub fn as_peek_result(&self) -> crate::PeekResult<'_, 'facet> {
228        crate::PeekResult {
229            value: self.value.as_peek(),
230            def: self.def,
231        }
232    }
233}
234
235#[cfg(test)]
236mod tests {
237    use super::*;
238
239    #[test]
240    fn poke_result_is_ok_is_err() {
241        let mut x: Result<i32, String> = Ok(42);
242        let poke = Poke::new(&mut x);
243        let res = poke.into_result().unwrap();
244        assert!(res.is_ok());
245        assert!(!res.is_err());
246
247        let mut y: Result<i32, String> = Err(String::from("nope"));
248        let poke = Poke::new(&mut y);
249        let res = poke.into_result().unwrap();
250        assert!(res.is_err());
251    }
252
253    #[test]
254    fn poke_result_set_ok_then_err() {
255        let mut x: Result<i32, String> = Err(String::from("initial"));
256        let poke = Poke::new(&mut x);
257        let mut res = poke.into_result().unwrap();
258        res.set_ok(7i32).unwrap();
259        assert_eq!(x, Ok(7));
260
261        let poke = Poke::new(&mut x);
262        let mut res = poke.into_result().unwrap();
263        res.set_err(String::from("oops")).unwrap();
264        assert_eq!(x, Err(String::from("oops")));
265    }
266
267    #[test]
268    fn poke_result_ok_mut() {
269        let mut x: Result<i32, String> = Ok(1);
270        let poke = Poke::new(&mut x);
271        let mut res = poke.into_result().unwrap();
272
273        {
274            let mut inner = res.ok_mut().unwrap();
275            inner.set(123i32).unwrap();
276        }
277        assert_eq!(x, Ok(123));
278    }
279
280    #[test]
281    fn poke_result_set_ok_from_heap() {
282        let mut x: Result<i32, String> = Err(String::from("initial"));
283        let poke = Poke::new(&mut x);
284        let mut res = poke.into_result().unwrap();
285
286        let hv = crate::Partial::alloc::<i32>()
287            .unwrap()
288            .set(42i32)
289            .unwrap()
290            .build()
291            .unwrap();
292        res.set_ok_from_heap(hv).unwrap();
293        assert_eq!(x, Ok(42));
294    }
295
296    #[test]
297    fn poke_result_set_err_from_heap() {
298        let mut x: Result<i32, String> = Ok(1);
299        let poke = Poke::new(&mut x);
300        let mut res = poke.into_result().unwrap();
301
302        let hv = crate::Partial::alloc::<String>()
303            .unwrap()
304            .set(String::from("boom"))
305            .unwrap()
306            .build()
307            .unwrap();
308        res.set_err_from_heap(hv).unwrap();
309        assert_eq!(x, Err(String::from("boom")));
310    }
311}