abi_stable/nonexhaustive_enum/
vtable.rs

1use std::{
2    cmp::{Ord, PartialEq, PartialOrd},
3    fmt::{Debug, Display},
4    hash::Hash,
5    marker::PhantomData,
6};
7
8use crate::{
9    erased_types::{c_functions, trait_objects, FormattingMode, InterfaceType},
10    inline_storage::InlineStorage,
11    marker_type::{ErasedObject, UnsafeIgnoredType},
12    nonexhaustive_enum::{
13        alt_c_functions, EnumInfo, GetEnumInfo, GetSerializeEnumProxy, NonExhaustive, SerializeEnum,
14    },
15    prefix_type::{panic_on_missing_fieldname, WithMetadata},
16    sabi_types::{RMut, RRef},
17    std_types::{RBoxError, RCmpOrdering, ROption, RResult, RString},
18    type_level::{
19        impl_enum::{Implemented, Unimplemented},
20        trait_marker,
21    },
22    utils::Transmuter,
23    StableAbi,
24};
25
26#[doc(hidden)]
27pub struct Private<T: ?Sized, S: ?Sized, I: ?Sized>(
28    PhantomData<(PhantomData<T>, PhantomData<S>, PhantomData<I>)>,
29);
30
31/// Gets the vtable of `NonExhaustive<Self,S,I>`.
32///
33/// This trait is only exposed for use in bounds,
34/// and cannot be implemented outside of `abi_stable`.
35pub trait GetVTable<S, I>: Sized {
36    // Using privacy to make it impossible to implement this trait outside this module.
37    #[doc(hidden)]
38    const __HIDDEN_10341423423__: Private<Self, S, I>;
39
40    #[doc(hidden)]
41    const VTABLE_VAL: NonExhaustiveVtable<Self, S, I>;
42
43    staticref! {
44        #[doc(hidden)]
45        const VTABLE_WM: WithMetadata<NonExhaustiveVtable<Self,S,I>> =
46            WithMetadata::new(Self::VTABLE_VAL)
47    }
48
49    /// The vtable
50    const VTABLE: NonExhaustiveVtable_Ref<Self, S, I> =
51        NonExhaustiveVtable_Ref(Self::VTABLE_WM.as_prefix());
52}
53
54/// The vtable for NonExhaustive.
55#[repr(C)]
56#[derive(StableAbi)]
57#[sabi(
58    bound(I: GetSerializeEnumProxy<E>),
59    bound(<I as GetSerializeEnumProxy<E>>::ProxyType: StableAbi),
60    not_stableabi(E,S,I),
61    missing_field(default),
62    kind(Prefix(prefix_ref_docs = "\
63        A reference to the vtable of a non-exhaustive enum,
64    ")),
65    with_field_indices,
66    //debug_print,
67)]
68pub struct NonExhaustiveVtable<E, S, I> {
69    pub(crate) _sabi_tys: UnsafeIgnoredType<(E, S, I)>,
70
71    /// The `EnumInfo` for the enum.
72    pub enum_info: &'static EnumInfo,
73
74    pub(crate) _sabi_drop: unsafe extern "C" fn(this: RMut<'_, ErasedObject>),
75
76    #[sabi(unsafe_opaque_field)]
77    pub(crate) _sabi_clone: Option<
78        unsafe extern "C" fn(
79            RRef<'_, ErasedObject>,
80            NonExhaustiveVtable_Ref<E, S, I>,
81        ) -> NonExhaustive<E, S, I>,
82    >,
83
84    pub(crate) _sabi_debug: Option<
85        unsafe extern "C" fn(
86            RRef<'_, ErasedObject>,
87            FormattingMode,
88            &mut RString,
89        ) -> RResult<(), ()>,
90    >,
91    pub(crate) _sabi_display: Option<
92        unsafe extern "C" fn(
93            RRef<'_, ErasedObject>,
94            FormattingMode,
95            &mut RString,
96        ) -> RResult<(), ()>,
97    >,
98    #[sabi(unsafe_change_type =
99        unsafe extern "C" fn(
100            RRef<'_, ErasedObject>
101        )->RResult< <I as GetSerializeEnumProxy<E>>::ProxyType, RBoxError>
102    )]
103    pub(crate) erased_sabi_serialize:
104        Option<unsafe extern "C" fn(RRef<'_, ErasedObject>) -> RResult<ErasedObject, RBoxError>>,
105    pub(crate) _sabi_partial_eq:
106        Option<unsafe extern "C" fn(RRef<'_, ErasedObject>, RRef<'_, ErasedObject>) -> bool>,
107    pub(crate) _sabi_cmp: Option<
108        unsafe extern "C" fn(RRef<'_, ErasedObject>, RRef<'_, ErasedObject>) -> RCmpOrdering,
109    >,
110    pub(crate) _sabi_partial_cmp: Option<
111        unsafe extern "C" fn(
112            RRef<'_, ErasedObject>,
113            RRef<'_, ErasedObject>,
114        ) -> ROption<RCmpOrdering>,
115    >,
116    #[sabi(last_prefix_field)]
117    pub(crate) _sabi_hash:
118        Option<unsafe extern "C" fn(RRef<'_, ErasedObject>, trait_objects::HasherObject<'_>)>,
119}
120
121unsafe impl<E, S, I> Sync for NonExhaustiveVtable<E, S, I> {}
122unsafe impl<E, S, I> Send for NonExhaustiveVtable<E, S, I> {}
123
124impl<E, S, I> GetVTable<S, I> for E
125where
126    S: InlineStorage,
127    I: InterfaceType,
128    E: GetEnumInfo,
129    I::Sync: RequiresSync<E, S, I>,
130    I::Send: RequiresSend<E, S, I>,
131    I::Clone: InitCloneField<E, S, I>,
132    I::Debug: InitDebugField<E, S, I>,
133    I::Display: InitDisplayField<E, S, I>,
134    I::Serialize: InitSerializeField<E, S, I>,
135    I::PartialEq: InitPartialEqField<E, S, I>,
136    I::PartialOrd: InitPartialOrdField<E, S, I>,
137    I::Ord: InitOrdField<E, S, I>,
138    I::Hash: InitHashField<E, S, I>,
139{
140    const __HIDDEN_10341423423__: Private<Self, S, I> = Private(PhantomData);
141
142    #[doc(hidden)]
143    const VTABLE_VAL: NonExhaustiveVtable<E, S, I> = NonExhaustiveVtable {
144        _sabi_tys: UnsafeIgnoredType::DEFAULT,
145        enum_info: E::ENUM_INFO,
146        _sabi_drop: alt_c_functions::drop_impl::<E>,
147        _sabi_clone: <I::Clone as InitCloneField<E, S, I>>::VALUE,
148        _sabi_debug: <I::Debug as InitDebugField<E, S, I>>::VALUE,
149        _sabi_display: <I::Display as InitDisplayField<E, S, I>>::VALUE,
150        erased_sabi_serialize: <I::Serialize as InitSerializeField<E, S, I>>::VALUE,
151        _sabi_partial_eq: <I::PartialEq as InitPartialEqField<E, S, I>>::VALUE,
152        _sabi_partial_cmp: <I::PartialOrd as InitPartialOrdField<E, S, I>>::VALUE,
153        _sabi_cmp: <I::Ord as InitOrdField<E, S, I>>::VALUE,
154        _sabi_hash: <I::Hash as InitHashField<E, S, I>>::VALUE,
155    };
156}
157
158type UnerasedSerializeFn<E, I> =
159    unsafe extern "C" fn(
160        RRef<'_, ErasedObject>,
161    ) -> RResult<<I as GetSerializeEnumProxy<E>>::ProxyType, RBoxError>;
162
163impl<E, S, I> NonExhaustiveVtable_Ref<E, S, I> {
164    pub(crate) fn serialize(self) -> UnerasedSerializeFn<E, I>
165    where
166        I: InterfaceType<Serialize = Implemented<trait_marker::Serialize>>,
167        I: GetSerializeEnumProxy<E>,
168    {
169        unsafe {
170            std::mem::transmute::<
171                unsafe extern "C" fn(RRef<'_, ErasedObject>) -> RResult<ErasedObject, RBoxError>,
172                UnerasedSerializeFn<E, I>,
173            >(self.priv_serialize())
174        }
175    }
176}
177
178use self::trait_bounds::*;
179pub mod trait_bounds {
180    use super::*;
181
182    macro_rules! declare_conditional_marker {
183        (
184            type $selector:ident;
185            trait $trait_name:ident[$self_:ident,$Filler:ident,$OrigPtr:ident]
186            where [ $($where_preds:tt)* ]
187        ) => (
188            pub trait $trait_name<$self_,$Filler,$OrigPtr>{}
189
190            impl<$self_,$Filler,$OrigPtr> $trait_name<$self_,$Filler,$OrigPtr>
191            for Unimplemented<trait_marker::$selector>
192            {}
193
194            impl<$self_,$Filler,$OrigPtr> $trait_name<$self_,$Filler,$OrigPtr>
195            for Implemented<trait_marker::$selector>
196            where
197                $($where_preds)*
198            {}
199        )
200    }
201
202    macro_rules! declare_field_initalizer {
203        (
204            type $selector:ident;
205            trait $trait_name:ident[$enum_:ident,$filler:ident,$interf:ident]
206            $( where_for_both[ $($where_preds_both:tt)* ] )?
207            where [ $($where_preds:tt)* ]
208            $priv_field:ident,$field:ident : $field_ty:ty;
209            field_index=$field_index:ident;
210            value=$field_value:expr,
211        ) => (
212            pub trait $trait_name<$enum_,$filler,$interf>
213            where
214                $($($where_preds_both)*)?
215            {
216                const VALUE:Option<$field_ty>;
217            }
218
219            impl<$enum_,$filler,$interf> $trait_name<$enum_,$filler,$interf>
220            for Unimplemented<trait_marker::$selector>
221            where
222                $($($where_preds_both)*)?
223            {
224                const VALUE:Option<$field_ty>=None;
225            }
226
227            impl<$enum_,$filler,$interf> $trait_name<$enum_,$filler,$interf>
228            for Implemented<trait_marker::$selector>
229            where
230                $($($where_preds_both)*)?
231                $($where_preds)*
232            {
233                const VALUE:Option<$field_ty>=Some($field_value);
234            }
235
236            impl<E,S,$interf> NonExhaustiveVtable_Ref<E,S,$interf>{
237                #[doc = concat!(
238                    "Fallibly accesses the `",
239                    stringify!($field),
240                    "` field, panicking if it doesn't exist."
241                )]
242
243                pub fn $field(self) -> $field_ty
244                where
245                    $interf:InterfaceType<$selector=Implemented<trait_marker::$selector>>,
246                {
247                    match self.$priv_field().into() {
248                        Some(v)=>v,
249                        None=>panic_on_missing_fieldname::<
250                            NonExhaustiveVtable<E,S,$interf>,
251                        >(
252                            Self::$field_index,
253                            self._prefix_type_layout(),
254                        )
255                    }
256                }
257            }
258        )
259    }
260
261    declare_conditional_marker! {
262        type Send;
263        trait RequiresSend[E,S,I]
264        where [ E:Send ]
265    }
266
267    declare_conditional_marker! {
268        type Sync;
269        trait RequiresSync[E,S,I]
270        where [ E:Sync ]
271    }
272
273    declare_field_initalizer! {
274        type Clone;
275        trait InitCloneField[E,S,I]
276        where_for_both[ E:GetEnumInfo, ]
277        where [ E:Clone ]
278        _sabi_clone,clone_:
279            unsafe extern "C" fn(
280                RRef<'_, ErasedObject>,
281                NonExhaustiveVtable_Ref<E,S,I>
282            )->NonExhaustive<E,S,I>;
283        field_index=field_index_for__sabi_clone;
284        value=alt_c_functions::clone_impl::<E,S,I>,
285    }
286    declare_field_initalizer! {
287        type Debug;
288        trait InitDebugField[E,S,I]
289        where [ E:Debug ]
290        _sabi_debug,debug:
291            unsafe extern "C" fn(
292                RRef<'_, ErasedObject>,
293                FormattingMode,
294                &mut RString,
295            )->RResult<(),()>;
296        field_index=field_index_for__sabi_debug;
297        value=c_functions::debug_impl::<E>,
298    }
299    declare_field_initalizer! {
300        type Display;
301        trait InitDisplayField[E,S,I]
302        where [ E:Display ]
303        _sabi_display,display:
304            unsafe extern "C" fn(
305                RRef<'_, ErasedObject>,
306                FormattingMode,
307                &mut RString,
308            )->RResult<(),()>;
309        field_index=field_index_for__sabi_display;
310        value=c_functions::display_impl::<E>,
311    }
312    declare_field_initalizer! {
313        type Serialize;
314        trait InitSerializeField[E,S,I]
315        where [ I:SerializeEnum<E> ]
316        erased_sabi_serialize,priv_serialize:
317            unsafe extern "C" fn(RRef<'_, ErasedObject>)->RResult<ErasedObject,RBoxError>;
318        field_index=field_index_for_erased_sabi_serialize;
319        value=unsafe{
320            Transmuter::<
321                unsafe extern "C" fn(
322                    RRef<'_, ErasedObject>
323                )->RResult<<I as SerializeEnum<E>>::Proxy,RBoxError>,
324                unsafe extern "C" fn(RRef<'_, ErasedObject>)->RResult<ErasedObject,RBoxError>
325            >{
326                from:alt_c_functions::serialize_impl::<E,I>
327            }.to
328        },
329    }
330    declare_field_initalizer! {
331        type PartialEq;
332        trait InitPartialEqField[E,S,I]
333        where_for_both[ E:GetEnumInfo, ]
334        where [ E:PartialEq ]
335        _sabi_partial_eq,partial_eq: unsafe extern "C" fn(RRef<'_, ErasedObject>,RRef<'_, ErasedObject>)->bool;
336        field_index=field_index_for__sabi_partial_eq;
337        value=alt_c_functions::partial_eq_impl::<E,S,I>,
338    }
339    declare_field_initalizer! {
340        type PartialOrd;
341        trait InitPartialOrdField[E,S,I]
342        where_for_both[ E:GetEnumInfo, ]
343        where [ E:PartialOrd ]
344        _sabi_partial_cmp,partial_cmp:
345            unsafe extern "C" fn(RRef<'_, ErasedObject>,RRef<'_, ErasedObject>)->ROption<RCmpOrdering>;
346        field_index=field_index_for__sabi_partial_cmp;
347        value=alt_c_functions::partial_cmp_ord::<E,S,I>,
348    }
349    declare_field_initalizer! {
350        type Ord;
351        trait InitOrdField[E,S,I]
352        where_for_both[ E:GetEnumInfo, ]
353        where [ E:Ord ]
354        _sabi_cmp,cmp:
355            unsafe extern "C" fn(
356                RRef<'_, ErasedObject>,
357                RRef<'_, ErasedObject>,
358            )->RCmpOrdering;
359        field_index=field_index_for__sabi_cmp;
360        value=alt_c_functions::cmp_ord::<E,S,I>,
361    }
362    declare_field_initalizer! {
363        type Hash;
364        trait InitHashField[E,S,I]
365        where [ E:Hash ]
366        _sabi_hash,hash: unsafe extern "C" fn(RRef<'_, ErasedObject>,trait_objects::HasherObject<'_>);
367        field_index=field_index_for__sabi_hash;
368        value=c_functions::hash_Hash::<E>,
369    }
370}