• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use core::fmt;
2 use core::mem::ManuallyDrop;
3 
4 #[repr(C)]
5 union DiplomatResultValue<T, E> {
6     ok: ManuallyDrop<T>,
7     err: ManuallyDrop<E>,
8 }
9 
10 /// A [`Result`]-like type that can be passed across the FFI boundary
11 /// as a value. Used internally to return [`Result`]s and [`Option`]s
12 /// from functions.
13 #[repr(C)]
14 pub struct DiplomatResult<T, E> {
15     value: DiplomatResultValue<T, E>,
16     pub is_ok: bool,
17 }
18 
19 /// A type to represent Option<T> over FFI.
20 ///
21 /// Used internally to handle `Option<T>` arguments and return types, and needs to be
22 /// used explicitly for optional struct fields.
23 pub type DiplomatOption<T> = DiplomatResult<T, ()>;
24 
25 impl<T, E> DiplomatResult<T, E> {
as_ref(&self) -> Result<&T, &E>26     pub fn as_ref(&self) -> Result<&T, &E> {
27         // Safety: we're only accessing the union variants when the flag is correct
28         unsafe {
29             if self.is_ok {
30                 Ok(&self.value.ok)
31             } else {
32                 Err(&self.value.err)
33             }
34         }
35     }
36 }
37 
38 impl<T> DiplomatOption<T> {
39     /// Helper for converting into an Option to avoid trait ambiguity errors with Into
40     #[inline]
into_option(self) -> Option<T>41     pub fn into_option(self) -> Option<T> {
42         self.into()
43     }
44 
45     /// Helper for converting into an Option with the inner type converted
46     #[inline]
into_converted_option<U: From<T>>(self) -> Option<U>47     pub fn into_converted_option<U: From<T>>(self) -> Option<U> {
48         self.into_option().map(Into::into)
49     }
50 }
51 
52 impl<T: Clone, E: Clone> Clone for DiplomatResult<T, E> {
clone(&self) -> Self53     fn clone(&self) -> Self {
54         unsafe {
55             if self.is_ok {
56                 Ok((*self.value.ok).clone()).into()
57             } else {
58                 Err((*self.value.err).clone()).into()
59             }
60         }
61     }
62 }
63 
64 impl<T, E> Drop for DiplomatResult<T, E> {
drop(&mut self)65     fn drop(&mut self) {
66         unsafe {
67             if self.is_ok {
68                 let _ = ManuallyDrop::take(&mut self.value.ok);
69             } else {
70                 let _ = ManuallyDrop::take(&mut self.value.err);
71             }
72         }
73     }
74 }
75 
76 impl<T, E> From<Result<T, E>> for DiplomatResult<T, E> {
from(result: Result<T, E>) -> Self77     fn from(result: Result<T, E>) -> Self {
78         match result {
79             Result::Ok(ok) => DiplomatResult {
80                 value: DiplomatResultValue {
81                     ok: ManuallyDrop::new(ok),
82                 },
83                 is_ok: true,
84             },
85 
86             Result::Err(err) => DiplomatResult {
87                 value: DiplomatResultValue {
88                     err: ManuallyDrop::new(err),
89                 },
90                 is_ok: false,
91             },
92         }
93     }
94 }
95 
96 impl<T> From<Option<T>> for DiplomatOption<T> {
from(option: Option<T>) -> Self97     fn from(option: Option<T>) -> Self {
98         option.ok_or(()).into()
99     }
100 }
101 
102 impl<T> From<DiplomatOption<T>> for Option<T> {
from(result: DiplomatOption<T>) -> Self103     fn from(result: DiplomatOption<T>) -> Self {
104         Result::<T, ()>::from(result).ok()
105     }
106 }
107 
108 impl<T, E> From<DiplomatResult<T, E>> for Result<T, E> {
from(mut result: DiplomatResult<T, E>) -> Result<T, E>109     fn from(mut result: DiplomatResult<T, E>) -> Result<T, E> {
110         unsafe {
111             if result.is_ok {
112                 Ok(ManuallyDrop::take(&mut result.value.ok))
113             } else {
114                 Err(ManuallyDrop::take(&mut result.value.err))
115             }
116         }
117     }
118 }
119 
120 impl<T: fmt::Debug, E: fmt::Debug> fmt::Debug for DiplomatResult<T, E> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result121     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
122         self.as_ref().fmt(f)
123     }
124 }
125