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}