abi_stable/nonexhaustive_enum/
traits.rs

1//! The traits releated to nonexhaustive enums.
2
3use std::{
4    cmp::{Eq, Ord},
5    fmt::{self, Debug},
6};
7
8use crate::{
9    std_types::{RBoxError, RStr},
10    type_layout::StartLen,
11    type_level::{
12        impl_enum::{Implemented, Unimplemented},
13        trait_marker,
14    },
15    InterfaceType,
16};
17
18/// Queries the marker type which describes the layout of this enum,
19/// for use in [`NonExhaustive`]'s [`StableAbi`] impl.
20///
21/// # Safety
22///
23/// `Self::Marker` must describe the layout of this enum,
24/// with the size and alignment of `Storage`,
25/// and using [`IsExhaustive::nonexhaustive`] to construct [`IsExhaustive`] in
26/// the `enum`'s [`TypeLayout`].
27///
28/// [`StableAbi`]: trait@crate::StableAbi
29/// [`TypeLayout`]: crate::type_layout::TypeLayout
30/// [`IsExhaustive`]: crate::type_layout::IsExhaustive
31/// [`IsExhaustive::nonexhaustive`]: crate::type_layout::IsExhaustive::nonexhaustive
32/// [`NonExhaustive`]: crate::nonexhaustive_enum::NonExhaustive
33///
34pub unsafe trait NonExhaustiveMarker<Storage>: GetEnumInfo {
35    /// A marker type which describes the layout of this enum
36    /// in its [`StableAbi`] impl.
37    type Marker;
38}
39
40/// Describes the discriminant of an enum,and its valid values.
41///
42/// # Safety
43///
44/// This must be an enum with a `#[repr(C)]` or `#[repr(SomeInteFgerType)]` attribute.
45///
46/// The `Discriminant` associated type must correspond to the type of
47/// this enum's discriminant.
48///
49/// The `DISCRIMINANTS` associated constant must be the values of
50/// this enum's discriminants.
51pub unsafe trait GetEnumInfo: Sized {
52    /// The type of the discriminant.
53    type Discriminant: ValidDiscriminant;
54
55    /// The default storage type,
56    /// used to store this enum inside `NonExhaustive<>`,
57    /// and allow the enum to grow in size in newer ABI compatible versions.
58    type DefaultStorage;
59
60    /// The default InterfaceType,
61    /// used to determine the traits that are required when constructing a `NonExhaustive<>`,
62    /// and are then usable afterwards.
63    type DefaultInterface;
64
65    /// Information about the enum.
66    const ENUM_INFO: &'static EnumInfo;
67
68    /// The values of the discriminants of each variant.
69    ///
70    const DISCRIMINANTS: &'static [Self::Discriminant];
71
72    /// Whether `discriminant` is one of the valid discriminants for this enum in this context.
73    fn is_valid_discriminant(discriminant: Self::Discriminant) -> bool;
74}
75
76pub use self::_enum_info::EnumInfo;
77mod _enum_info {
78    use super::*;
79
80    /// Contains miscelaneous information about an enum.
81    #[repr(C)]
82    #[derive(StableAbi)]
83    pub struct EnumInfo {
84        /// The name of a type,eg:`Vec` for a `Vec<u8>`.
85        type_name: RStr<'static>,
86
87        strings: RStr<'static>,
88
89        /// The range inside of strings with the names of the variants of the enum,separated by ';'.
90        variant_names_start_len: StartLen,
91    }
92
93    impl EnumInfo {
94        #[doc(hidden)]
95        pub const fn _for_derive(
96            type_name: RStr<'static>,
97            strings: RStr<'static>,
98            variant_names_start_len: StartLen,
99        ) -> Self {
100            Self {
101                type_name,
102                strings,
103                variant_names_start_len,
104            }
105        }
106
107        /// The name of a type,eg:`Foo` for a `Foo<u8>`.
108        pub fn type_name(&self) -> &'static str {
109            self.type_name.as_str()
110        }
111
112        /// The names of the variants of the enum,separated by ';'.
113        pub fn variant_names(&self) -> &'static str {
114            &self.strings.as_str()[self.variant_names_start_len.to_range()]
115        }
116    }
117}
118
119impl EnumInfo {
120    /// Gets an iterator over the names of the variants of the enum.
121    pub fn variant_names_iter(
122        &self,
123    ) -> impl Iterator<Item = &'static str> + 'static + Debug + Clone {
124        self.variant_names().split_terminator(';')
125    }
126}
127
128impl Debug for EnumInfo {
129    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130        f.debug_struct("EnumInfo")
131            .field("type_name", &self.type_name())
132            .field("variant_names", &IteratorAsList(self.variant_names_iter()))
133            .finish()
134    }
135}
136
137struct IteratorAsList<I>(I);
138
139impl<I, T> Debug for IteratorAsList<I>
140where
141    I: Iterator<Item = T> + Clone,
142    T: Debug,
143{
144    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145        f.debug_list().entries(self.0.clone()).finish()
146    }
147}
148
149/////////////////////////////////////////////////////////////
150
151/// Marker trait for types that abi_stable supports as enum discriminants.
152///
153/// This trait cannot be implemented outside of this module.
154pub trait ValidDiscriminant: Sealed + Copy + Eq + Ord + Debug + Send + Sync + 'static {}
155
156mod sealed {
157    pub trait Sealed {}
158}
159use self::sealed::Sealed;
160
161macro_rules! impl_valid_discriminant {
162    (
163        $($ty:ty),* $(,)*
164    ) => (
165        $(
166            impl ValidDiscriminant for $ty{}
167            impl Sealed for $ty{}
168        )*
169    )
170}
171
172impl_valid_discriminant! {u8,i8,u16,i16,u32,i32,u64,i64,usize,isize}
173
174///////////////////////////////////////////////////////////////////////////////
175
176/// Describes how some enum is serialized.
177///
178/// This is generally implemented by the interface of an enum
179/// (`Enum_Interface` for `Enum`),which also implements [`InterfaceType`]).
180///
181/// # Example
182///
183/// ```rust
184/// use abi_stable::{
185///     external_types::RawValueBox,
186///     nonexhaustive_enum::{NonExhaustive, SerializeEnum},
187///     std_types::{RBoxError, RString},
188///     StableAbi,
189/// };
190///
191/// let ne = NonExhaustive::new(Foo::C{name: "world".into()});
192/// assert_eq!(serde_json::to_string(&ne).unwrap(), r#"{"C":{"name":"world"}}"#);
193///
194///
195/// #[repr(u8)]
196/// #[derive(StableAbi, Debug, PartialEq, Eq, serde::Serialize)]
197/// #[sabi(kind(WithNonExhaustive(
198///     size = 64,
199///     traits(Debug, PartialEq, Eq, Serialize)
200/// )))]
201/// pub enum Foo {
202///     A,
203///     B(i8),
204///     C {
205///         name: RString
206///     },
207/// }
208///
209/// impl SerializeEnum<Foo> for Foo_Interface {
210///     /// A type that `Foo` is converted into to be serialized.
211///     type Proxy = RawValueBox;
212///
213///     fn serialize_enum(this: &Foo) -> Result<RawValueBox, RBoxError> {
214///         match serde_json::value::to_raw_value(&this) {
215///             Ok(v) => Ok(v.into()),
216///             Err(e) => Err(RBoxError::new(e)),
217///         }
218///     }
219/// }
220/// ```
221///
222/// [`InterfaceType`]: ../trait.InterfaceType.html
223pub trait SerializeEnum<Enum>: InterfaceType {
224    /// The intermediate type the `Enum` is converted into,to serialize it.
225    type Proxy;
226
227    /// Serializes an enum into its proxy type.
228    fn serialize_enum(this: &Enum) -> Result<Self::Proxy, RBoxError>;
229}
230
231#[doc(hidden)]
232pub trait GetSerializeEnumProxy<E>: InterfaceType {
233    type ProxyType;
234}
235
236impl<I, E, PT> GetSerializeEnumProxy<E> for I
237where
238    I: InterfaceType,
239    I: GetSerializeEnumProxyHelper<E, <I as InterfaceType>::Serialize, ProxyType = PT>,
240{
241    type ProxyType = PT;
242}
243
244#[doc(hidden)]
245pub trait GetSerializeEnumProxyHelper<E, IS>: InterfaceType {
246    type ProxyType;
247}
248
249impl<I, E> GetSerializeEnumProxyHelper<E, Implemented<trait_marker::Serialize>> for I
250where
251    I: InterfaceType,
252    I: SerializeEnum<E>,
253{
254    type ProxyType = <I as SerializeEnum<E>>::Proxy;
255}
256
257impl<I, E> GetSerializeEnumProxyHelper<E, Unimplemented<trait_marker::Serialize>> for I
258where
259    I: InterfaceType,
260{
261    type ProxyType = ();
262}
263
264///////////////////////////////////////
265
266/// Describes how a nonexhaustive enum is deserialized.
267///
268/// Generally this delegates to a library function,
269/// so that the implementation can be delegated
270/// to the `implementation crate`.
271///
272/// This is generally implemented by the interface of an enum
273/// (`Enum_Interface` for `Enum`),which also implements [`InterfaceType`]).
274///
275/// The `NE` type parameter is expected to be [`NonExhaustive`].
276///
277/// # Example
278///
279/// ```rust
280/// use abi_stable::{
281///     nonexhaustive_enum::{DeserializeEnum, NonExhaustive, NonExhaustiveFor},
282///     external_types::RawValueRef,
283///     std_types::{RBoxError, RResult, ROk, RErr, RStr, RString},
284///     rstr, StableAbi,
285/// };
286///
287/// let input = r#"{"C": {"name": "hello"}}"#;
288/// let ne = serde_json::from_str::<NonExhaustiveFor<Foo>>(input).unwrap();
289/// assert_eq!(ne, Foo::C{name: "hello".into()});
290///
291///
292/// #[repr(u8)]
293/// #[derive(StableAbi, Debug, PartialEq, Eq, serde::Deserialize)]
294/// #[sabi(kind(WithNonExhaustive(
295///     size = 64,
296///     traits(Debug, PartialEq, Eq, Deserialize)
297/// )))]
298/// pub enum Foo {
299///     A,
300///     B(i8),
301///     C {
302///         name: RString
303///     },
304/// }
305///
306/// impl<'borr> DeserializeEnum<'borr, NonExhaustiveFor<Foo>> for Foo_Interface {
307///     /// The intermediate type the `NE` is converted from,to deserialize it.
308///     type Proxy = RawValueRef<'borr>;
309///
310///     /// Deserializes an enum from its proxy type.
311///     fn deserialize_enum(s: Self::Proxy) -> Result<NonExhaustiveFor<Foo>, RBoxError> {
312///         deserialize_foo(s.get_rstr()).into_result()
313///     }
314/// }
315///
316/// /////////////
317/// // everything below could be defined in an implementation crate
318/// //
319/// // This allows the library that defines the enum to add variants,
320/// // and deserialize the variants that it added,
321/// // regardless of whether the dependent crates know about those variants.
322///
323/// extern "C" fn deserialize_foo(s: RStr<'_>) -> RResult<NonExhaustiveFor<Foo>, RBoxError> {
324///     abi_stable::extern_fn_panic_handling!{
325///         match serde_json::from_str::<Foo>(s.into()) {
326///             Ok(x) => ROk(NonExhaustive::new(x)),
327///             Err(e) => RErr(RBoxError::new(e)),
328///         }
329///     }
330/// }
331///
332/// ```
333///
334/// [`InterfaceType`]: crate::InterfaceType
335/// [`NonExhaustive`]: crate::nonexhaustive_enum::NonExhaustive
336pub trait DeserializeEnum<'borr, NE>: InterfaceType {
337    /// The intermediate type the `NonExhaustive` is converted from,to deserialize it.
338    type Proxy;
339
340    /// Deserializes an enum from its proxy type.
341    fn deserialize_enum(s: Self::Proxy) -> Result<NE, RBoxError>;
342}