abi_stable_derive/
impl_interfacetype.rs

1//! The implementation of both the `#[sabi(impl_InterfaceType())]` helper attributes,
2//! and the `impl_InterfaceType!{}` macro.
3
4use std::collections::HashMap;
5
6#[allow(unused_imports)]
7use core_extensions::SelfOps;
8
9use quote::{quote, quote_spanned, ToTokens};
10
11use syn::Ident;
12
13use as_derive_utils::to_token_fn::ToTokenFnMut;
14
15use crate::parse_utils::parse_str_as_ident;
16
17pub(crate) mod attribute_parsing;
18mod macro_impl;
19
20pub(crate) use self::{
21    attribute_parsing::{parse_impl_interfacetype, ImplInterfaceType},
22    macro_impl::the_macro,
23};
24
25//////////////////////
26
27/// The default value for an associated type.
28#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
29pub enum DefaultVal {
30    /// The value of the associated type is `Unimplemented<trait_marker::AssocTypeName>`
31    Unimplemented,
32    /// The value of the associated type is `Implemented<trait_marker::AssocTypeName>`
33    Implemented,
34    /// The associated type is `#[doc(hidden)]`,
35    /// to signal to users that the trait is not supposed to be implemented manually,
36    Hidden,
37}
38
39impl From<bool> for DefaultVal {
40    fn from(b: bool) -> Self {
41        if b {
42            DefaultVal::Implemented
43        } else {
44            DefaultVal::Unimplemented
45        }
46    }
47}
48
49//////////////////////
50
51/// The trait object implementations (either RObject or DynTrait)
52/// that a trait can be used with.
53#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
54pub struct UsableBy {
55    robject: bool,
56    dyn_trait: bool,
57}
58
59impl UsableBy {
60    pub const DYN_TRAIT: Self = Self {
61        robject: false,
62        dyn_trait: true,
63    };
64    pub const ROBJECT_AND_DYN_TRAIT: Self = Self {
65        robject: true,
66        dyn_trait: true,
67    };
68
69    pub const fn robject(&self) -> bool {
70        self.robject
71    }
72    pub const fn dyn_trait(&self) -> bool {
73        self.dyn_trait
74    }
75}
76
77//////////////////////
78
79/// Information about a trait that is usable in RObject and/or DynTrait.
80#[derive(Debug, Copy, Clone)]
81pub struct UsableTrait {
82    pub which_trait: WhichTrait,
83    pub name: &'static str,
84    pub full_path: &'static str,
85}
86
87macro_rules! usable_traits {
88    (
89        $(
90            $field:ident=
91            (
92                $which_trait:ident,
93                $full_path:expr,
94                $default_value:expr,
95                $usable_by:expr
96            ),
97        )*
98    ) => (
99        /// A list of all the traits usable in RObject and/or DynTrait.
100        pub static TRAIT_LIST:&[UsableTrait]=&[$(
101            UsableTrait{
102                name:stringify!($which_trait),
103                which_trait:WhichTrait::$which_trait,
104                full_path:$full_path,
105            },
106        )*];
107
108        /// Represents all the trait usable in `RObject` and/or `DynTrait`,
109        /// usable as an index for `TraitStruct`.
110        #[repr(u8)]
111        #[derive(Debug,Copy,Clone,PartialEq,Eq,Ord,PartialOrd,Hash)]
112        pub enum WhichTrait{
113            $($which_trait,)*
114        }
115
116
117        impl WhichTrait{
118            pub fn default_value(self)->bool{
119                match self {
120                    $( WhichTrait::$which_trait=>$default_value, )*
121                }
122            }
123            pub fn usable_by(self)->UsableBy{
124                match self {
125                    $( WhichTrait::$which_trait=>$usable_by, )*
126                }
127            }
128        }
129
130        /// An generic struct with all the traits usable in RObject and/or DynTrait,
131        /// indexable by `WhichTrait`.
132        ///
133        #[derive(Debug,Copy,Clone,Default)]
134        pub struct TraitStruct<T>{
135            $(pub $field:T,)*
136        }
137
138        impl TraitStruct<UsableTrait>{
139            pub const TRAITS:Self=TraitStruct{$(
140                $field:UsableTrait{
141                    name:stringify!($which_trait),
142                    which_trait:WhichTrait::$which_trait,
143                    full_path:$full_path,
144                },
145            )*};
146        }
147
148        impl<T> TraitStruct<T>{
149            pub fn as_ref(&self)->TraitStruct<&T>{
150                TraitStruct{
151                    $($field:&self.$field,)*
152                }
153            }
154
155            pub fn map<F,U>(self,mut f:F)->TraitStruct<U>
156            where F:FnMut(WhichTrait,T)->U
157            {
158                TraitStruct{
159                    $($field:f(WhichTrait::$which_trait,self.$field),)*
160                }
161            }
162
163            // Bad clippy, you're bad.
164            #[allow(clippy::wrong_self_convention)]
165            pub fn to_vec(self)->Vec<T>{
166                vec![
167                    $( self.$field ,)*
168                ]
169            }
170        }
171
172        impl<T> ::std::ops::Index<WhichTrait> for TraitStruct<T>{
173            type Output=T;
174            fn index(&self, index: WhichTrait) -> &Self::Output {
175                match index {
176                    $( WhichTrait::$which_trait=>&self.$field, )*
177                }
178            }
179        }
180
181        impl<T> ::std::ops::IndexMut<WhichTrait> for TraitStruct<T>{
182            fn index_mut(&mut self, index: WhichTrait) -> &mut Self::Output {
183                match index {
184                    $( WhichTrait::$which_trait=>&mut self.$field, )*
185                }
186            }
187        }
188    )
189}
190
191use self::UsableBy as UB;
192
193usable_traits! {
194    clone=(Clone,"::std::clone::Clone",false,UB::ROBJECT_AND_DYN_TRAIT),
195    default=(Default,"::std::default::Default",false,UB::DYN_TRAIT),
196    display=(Display,"::std::fmt::Display",false,UB::ROBJECT_AND_DYN_TRAIT),
197    debug=(Debug,"::std::fmt::Debug",false,UB::ROBJECT_AND_DYN_TRAIT),
198    serialize=(Serialize,"::serde::Serialize",false,UB::DYN_TRAIT),
199    eq=(Eq,"::std::cmp::Eq",false,UB::DYN_TRAIT),
200    partial_eq=(PartialEq,"::std::cmp::PartialEq",false,UB::DYN_TRAIT),
201    ord=(Ord,"::std::cmp::Ord",false,UB::DYN_TRAIT),
202    partial_ord=(PartialOrd,"::std::cmp::PartialOrd",false,UB::DYN_TRAIT),
203    hash=(Hash,"::std::hash::Hash",false,UB::DYN_TRAIT),
204    deserialize=(Deserialize,"::serde::Deserialize",false,UB::DYN_TRAIT),
205    send=(Send,"::std::marker::Send",false ,UB::ROBJECT_AND_DYN_TRAIT),
206    sync=(Sync,"::std::marker::Sync",false ,UB::ROBJECT_AND_DYN_TRAIT),
207    iterator=(Iterator,"::std::iter::Iterator",false,UB::DYN_TRAIT),
208    double_ended_iterator=(
209        DoubleEndedIterator,"::std::iter::DoubleEndedIterator",false,UB::DYN_TRAIT
210    ),
211    fmt_write=(FmtWrite,"::std::fmt::Write",false,UB::DYN_TRAIT),
212    io_write=(IoWrite,"::std::io::Write",false,UB::DYN_TRAIT),
213    io_seek=(IoSeek,"::std::io::Seek",false,UB::DYN_TRAIT),
214    io_read=(IoRead,"::std::io::Read",false,UB::DYN_TRAIT),
215    io_buf_read=(IoBufRead,"::std::io::BufRead",false,UB::DYN_TRAIT),
216    error=(Error,"::std::error::Error",false,UB::ROBJECT_AND_DYN_TRAIT),
217    unpin=(Unpin,"::std::marker::Unpin",false,UB::ROBJECT_AND_DYN_TRAIT),
218}
219
220pub(crate) fn private_associated_type() -> syn::Ident {
221    parse_str_as_ident("define_this_in_the_impl_InterfaceType_macro")
222}
223
224//////////////////////////////////////////////////////////////////////////////
225
226/// Returns a tokenizer
227/// which prints an implementation of InterfaceType for `name`,
228/// with `impl_interfacetype` determining the associated types.
229pub(crate) fn impl_interfacetype_tokenizer<'a>(
230    name: &'a Ident,
231    generics: &'a syn::Generics,
232    impl_interfacetype: Option<&'a ImplInterfaceType>,
233) -> impl ToTokens + 'a {
234    ToTokenFnMut::new(move |ts| {
235        let ImplInterfaceType { impld, unimpld } = match impl_interfacetype {
236            Some(x) => x,
237            None => return,
238        };
239
240        let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
241
242        let const_ident = crate::parse_utils::parse_str_as_ident(&format!(
243            "_impl_InterfaceType_constant_{}",
244            name,
245        ));
246
247        let impld_a = impld;
248        let impld_b = impld;
249
250        let unimpld_a = unimpld;
251        let unimpld_b = unimpld;
252
253        let priv_assocty = private_associated_type();
254
255        quote!(
256            const #const_ident:()={
257                use abi_stable::{
258                    type_level::{
259                        impl_enum::{
260                            Implemented as __Implemented,
261                            Unimplemented as __Unimplemented,
262                        },
263                        trait_marker,
264                    },
265                };
266                impl #impl_generics abi_stable::InterfaceType for #name #ty_generics
267                #where_clause
268                {
269                    #( type #impld_a=__Implemented<trait_marker::#impld_b>; )*
270                    #( type #unimpld_a=__Unimplemented<trait_marker::#unimpld_b>; )*
271                    type #priv_assocty=();
272                }
273            };
274        )
275        .to_tokens(ts);
276    })
277}
278
279//////////////////////////////////////////////////////////////////////////////