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
31pub trait GetVTable<S, I>: Sized {
36 #[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 const VTABLE: NonExhaustiveVtable_Ref<Self, S, I> =
51 NonExhaustiveVtable_Ref(Self::VTABLE_WM.as_prefix());
52}
53
54#[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 )]
68pub struct NonExhaustiveVtable<E, S, I> {
69 pub(crate) _sabi_tys: UnsafeIgnoredType<(E, S, I)>,
70
71 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}