use crate::{
impl_interfacetype::private_associated_type,
my_visibility::{RelativeVis, VisibilityKind},
parse_utils::parse_str_as_ident,
workaround::token_stream_to_string,
*,
};
use std::marker::PhantomData;
use proc_macro2::TokenStream as TokenStream2;
use quote::TokenStreamExt;
use syn::ItemTrait;
use as_derive_utils::{
gen_params_in::{GenParamsIn, InWhat},
to_token_fn::ToTokenFnMut,
};
mod attribute_parsing;
mod common_tokens;
mod impl_delegations;
mod lifetime_unelider;
mod method_where_clause;
mod methods_tokenizer;
mod replace_self_path;
mod trait_definition;
#[cfg(test)]
mod tests;
use self::{
attribute_parsing::SabiTraitOptions,
common_tokens::{CommonTokens, IsStaticTrait, LifetimeTokens},
lifetime_unelider::LifetimeUnelider,
method_where_clause::MethodWhereClause,
methods_tokenizer::MethodsTokenizer,
trait_definition::{TraitDefinition, TraitMethod},
};
#[allow(dead_code)]
#[derive(Copy, Clone)]
struct TokenizerParams<'a> {
arenas: &'a Arenas,
ctokens: &'a CommonTokens,
config: &'a SabiTraitOptions<'a>,
trait_def: &'a TraitDefinition<'a>,
vis: VisibilityKind<'a>,
submod_vis: RelativeVis<'a>,
totrait_def: &'a TraitDefinition<'a>,
vtable_trait_decl: &'a TraitDefinition<'a>,
vtable_trait_impl: &'a TraitDefinition<'a>,
trait_ident: &'a syn::Ident,
trait_to: &'a syn::Ident,
trait_backend: &'a syn::Ident,
trait_interface: &'a syn::Ident,
make_vtable_ident: &'a syn::Ident,
trait_cto_ident: &'a syn::Ident,
lt_tokens: &'a LifetimeTokens,
}
pub fn derive_sabi_trait(item: ItemTrait) -> Result<TokenStream2, syn::Error> {
let arenas = Arenas::default();
let arenas = &arenas;
let ctokens = CommonTokens::new();
let ctokens = &ctokens;
let trait_ident = &item.ident;
let config = &self::attribute_parsing::parse_attrs_for_sabi_trait(&item, arenas, ctokens)?;
let trait_def = &config.trait_definition;
let lt_tokens = &LifetimeTokens::new(trait_def.is_static);
let vis = trait_def.vis;
let submod_vis = trait_def.submod_vis;
let totrait_def = &trait_def.replace_self(WhichItem::TraitObjectImpl)?;
let vtable_trait_decl = &trait_def.replace_self(WhichItem::VtableDecl)?;
let vtable_trait_impl = &trait_def.replace_self(WhichItem::VtableImpl)?;
let generated_mod = &parse_str_as_ident(&format!("{}_trait", trait_ident));
let trait_to = &parse_str_as_ident(&format!("{}_TO", trait_ident));
let trait_backend = &parse_str_as_ident(&format!("{}_Backend", trait_ident));
let trait_interface = &parse_str_as_ident(&format!("{}_Interface", trait_ident));
let make_vtable_ident = &parse_str_as_ident(&format!("{}_MV", trait_ident));
let trait_cto_ident = &parse_str_as_ident(&format!("{}_CTO", trait_ident));
let mut mod_contents = TokenStream2::default();
let tokenizer_params = TokenizerParams {
arenas,
ctokens,
config,
lt_tokens,
trait_def,
vis,
submod_vis,
totrait_def,
vtable_trait_decl,
vtable_trait_impl,
trait_ident,
trait_to,
trait_backend,
trait_interface,
make_vtable_ident,
trait_cto_ident,
};
first_items(tokenizer_params, &mut mod_contents);
constructor_items(tokenizer_params, &mut mod_contents);
trait_and_impl(tokenizer_params, &mut mod_contents);
methods_impls(tokenizer_params, &mut mod_contents)?;
declare_vtable(tokenizer_params, &mut mod_contents);
vtable_impl(tokenizer_params, &mut mod_contents);
impl_delegations::delegated_impls(tokenizer_params, &mut mod_contents);
let doc_hidden_attr = config.doc_hidden_attr;
let mod_docs = if doc_hidden_attr.is_none() {
Some(format!(
"This module is generated by the \
[`#[sabi_trait]`](macro@::abi_stable::sabi_trait) \
attribute on \
[{trait_}](trait@{trait_})",
trait_ = trait_ident,
))
} else {
None
}
.into_iter();
let mut tokens = quote!(
#doc_hidden_attr
#[doc(inline)]
#vis use self::#generated_mod::{
#trait_to,
#trait_ident,
#trait_cto_ident,
};
#doc_hidden_attr
#(#[doc = #mod_docs])*
#[allow(explicit_outlives_requirements)]
#vis mod #generated_mod{
#mod_contents
}
);
if config.debug_output_tokens {
let tokens_str = tokens.to_string();
tokens.append_all(quote!(
pub const TOKENS: &'static str = #tokens_str;
));
}
if config.debug_print_trait {
panic!("\n\n\n{}\n\n\n", token_stream_to_string(tokens.clone()));
}
Ok(tokens)
}
fn first_items(
TokenizerParams {
config,
ctokens,
lt_tokens,
trait_def,
submod_vis,
trait_to,
trait_backend,
trait_interface,
trait_cto_ident,
..
}: TokenizerParams,
mod_: &mut TokenStream2,
) {
let trait_ident = trait_def.name;
let doc_hidden_attr = config.doc_hidden_attr;
let mut uto_params = trait_def.generics_tokenizer(
InWhat::ItemDecl,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt_erasedptr,
);
uto_params.set_no_bounds();
let mut gen_params_header_rref = trait_def.generics_tokenizer(
InWhat::ImplHeader,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt_sub_lt,
);
gen_params_header_rref.set_no_bounds();
let gen_params_use_to_rref = trait_def.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt_rref,
);
let uto_params_use = trait_def.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt_erasedptr,
);
let mut trait_interface_header = trait_def.generics_tokenizer(
InWhat::ImplHeader,
WithAssocTys::Yes(WhichSelf::NoSelf),
&ctokens.ts_empty,
);
trait_interface_header.set_no_bounds();
let mut trait_interface_decl = trait_def.generics_tokenizer(
InWhat::ItemDecl,
WithAssocTys::Yes(WhichSelf::NoSelf),
&ctokens.ts_empty,
);
trait_interface_decl.set_no_bounds();
let trait_interface_use = trait_def.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::NoSelf),
&ctokens.ts_empty,
);
let to_params = trait_def.generics_tokenizer(
InWhat::ItemDecl,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt_erasedptr,
);
let where_preds = (&trait_def.where_preds).into_iter();
let vtable_args = trait_def.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::NoSelf),
&ctokens.ts_unit_erasedptr,
);
let impld_traits = trait_def.impld_traits.iter().map(|x| &x.ident);
let impld_traits_a = impld_traits.clone();
let impld_traits_b = impld_traits.clone();
let unimpld_traits_a = trait_def.unimpld_traits.iter().cloned();
let unimpld_traits_b = trait_def.unimpld_traits.iter().cloned();
let priv_assocty = private_associated_type();
let object = match trait_def.which_object {
WhichObject::DynTrait => quote!(DynTrait),
WhichObject::RObject => quote!(RObject),
};
let vtable_argument = match trait_def.which_object {
WhichObject::DynTrait => quote!(__sabi_re::PrefixRef<VTable_Prefix<#vtable_args>>),
WhichObject::RObject => quote!(VTable_Prefix<#vtable_args>),
};
let dummy_struct_generics = trait_def.generics_tokenizer(
InWhat::DummyStruct,
WithAssocTys::Yes(WhichSelf::NoSelf),
&ctokens.ts_empty,
);
let used_trait_object = quote!(#trait_backend<#uto_params_use>);
let trait_flags = &trait_def.trait_flags;
let send_syncness = match (trait_flags.sync, trait_flags.send) {
(false, false) => "UnsyncUnsend",
(false, true) => "UnsyncSend",
(true, false) => "SyncUnsend",
(true, true) => "SyncSend",
}
.piped(parse_str_as_ident);
let mut trait_backend_docs = String::new();
let mut trait_interface_docs = String::new();
let mut trait_to_docs = String::new();
let mut trait_cto_docs = String::new();
if doc_hidden_attr.is_none() {
trait_backend_docs = format!(
"An alias for the underlying implementation of \
[`{trait_to}`](struct@{trait_to}).\
",
trait_to = trait_to
);
trait_interface_docs = format!(
"A marker type describing the traits that are required when constructing \
[`{trait_to}`](struct@{trait_to}),\
and are then implemented by it,
by implementing the
[`InterfaceType`](::abi_stable::InterfaceType)
trait.",
trait_to = trait_to
);
trait_to_docs = format!(
"\
The trait object for [{Trait}](trait@{Trait}).\n\
\n\
There are extra methods on the `obj` field.\n
",
Trait = trait_ident
);
trait_cto_docs = format!(
"A type alias for the const-constructible \
[`{trait_to}`](struct@{trait_to}).",
trait_to = trait_to
);
}
let one_lt = <_tokens.one_lt;
quote!(
use super::*;
use abi_stable::sabi_trait::reexports::{*,__sabi_re};
use self::#trait_ident as __Trait;
#[doc=#trait_backend_docs]
#submod_vis type #trait_backend<#uto_params>=
__sabi_re::#object<
#one_lt
_ErasedPtr,
#trait_interface<#trait_interface_use>,
#vtable_argument
>;
#[doc=#trait_cto_docs]
#submod_vis type #trait_cto_ident<#gen_params_header_rref>=
#trait_to<#gen_params_use_to_rref>;
#[doc=#trait_interface_docs]
#[repr(C)]
#[derive(::abi_stable::StableAbi)]
#submod_vis struct #trait_interface<#trait_interface_decl>(
__sabi_re::NonOwningPhantom<(#dummy_struct_generics)>
);
impl<#trait_interface_header> #trait_interface<#trait_interface_use> {
#submod_vis const NEW:Self=#trait_interface(__sabi_re::NonOwningPhantom::NEW);
}
#[doc=#trait_to_docs]
#[repr(transparent)]
#[derive(::abi_stable::StableAbi)]
#[sabi(bound(#used_trait_object: ::abi_stable::StableAbi))]
#submod_vis struct #trait_to<#to_params>
where
_ErasedPtr:__GetPointerKind,
#(#where_preds)*
{
#submod_vis obj:#used_trait_object,
_marker:__sabi_re::UnsafeIgnoredType< __sabi_re::#send_syncness >,
}
const __inside_generated_mod:()={
use abi_stable::{
InterfaceType,
type_level::{
impl_enum::{Implemented,Unimplemented},
trait_marker,
},
};
impl<#trait_interface_header>
abi_stable::InterfaceType
for #trait_interface<#trait_interface_use>
{
#( type #impld_traits_a=Implemented<trait_marker::#impld_traits_b>; )*
#( type #unimpld_traits_a=Unimplemented<trait_marker::#unimpld_traits_b>; )*
type #priv_assocty=();
}
};
)
.to_tokens(mod_);
}
fn constructor_items(params: TokenizerParams<'_>, mod_: &mut TokenStream2) {
let TokenizerParams {
ctokens,
totrait_def,
submod_vis,
trait_ident,
trait_to,
trait_backend,
trait_interface,
lt_tokens,
make_vtable_ident,
..
} = params;
let doc_hidden_attr = params.config.doc_hidden_attr;
let trait_params =
totrait_def.generics_tokenizer(InWhat::ItemUse, WithAssocTys::No, &ctokens.empty_ts);
let assoc_tys_a = totrait_def.assoc_tys.keys();
let assoc_tys_b = assoc_tys_a.clone();
let assoc_tys_c = assoc_tys_a.clone();
let assoc_tys_d = assoc_tys_a.clone();
let assoc_tys_e = assoc_tys_a.clone();
let assoc_tys_f = assoc_tys_a.clone();
let mut make_vtable_args = totrait_def.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::No,
&ctokens.ts_make_vtable_args,
);
make_vtable_args.skip_lifetimes();
let mut make_vtable_args_const = totrait_def.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::No,
&ctokens.ts_make_vtable_args_const,
);
make_vtable_args_const.skip_lifetimes();
let fn_can_it_downcast_arg = match totrait_def.which_object {
WhichObject::DynTrait => quote!(Downcasting),
WhichObject::RObject => quote!(),
};
let trait_interface_use = totrait_def.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::NoSelf),
&ctokens.ts_empty,
);
let one_lt = <_tokens.one_lt;
let extra_constraints_ptr = match totrait_def.which_object {
WhichObject::DynTrait => quote!(
#trait_interface<#trait_interface_use>:
::abi_stable::erased_types::InterfaceType,
__sabi_re::DynTraitVTable_Ref<
#one_lt
_OrigPtr::TransmutedPtr,
#trait_interface<#trait_interface_use>,
>:
__sabi_re::MakeDynTraitVTable<
#one_lt
_OrigPtr::PtrTarget,
_OrigPtr,
Downcasting
>,
),
WhichObject::RObject => quote!(),
};
let extra_constraints_value = match totrait_def.which_object {
WhichObject::DynTrait => quote!(
#trait_interface<#trait_interface_use>:
::abi_stable::erased_types::InterfaceType,
__sabi_re::DynTraitVTable_Ref<
#one_lt
__sabi_re::RBox<()>,
#trait_interface<#trait_interface_use>,
>:
__sabi_re::MakeDynTraitVTable<
#one_lt
_Self,
__sabi_re::RBox<_Self>,
Downcasting
>,
),
WhichObject::RObject => quote!(),
};
let extra_constraints_const = match totrait_def.which_object {
WhichObject::DynTrait => quote!(
#trait_interface<#trait_interface_use>:
::abi_stable::erased_types::InterfaceType,
__sabi_re::DynTraitVTable_Ref<
#one_lt
__sabi_re::RRef<'_sub, ()>,
#trait_interface<#trait_interface_use>,
>:
__sabi_re::MakeDynTraitVTable<
#one_lt
_Self,
&'_sub _Self,
Downcasting
>,
),
WhichObject::RObject => quote!(),
};
let gen_params_header = totrait_def.generics_tokenizer(
InWhat::ImplHeader,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt_erasedptr,
);
let gen_params_use_to = totrait_def.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt_erasedptr,
);
let gen_params_header_rbox = totrait_def.generics_tokenizer(
InWhat::ImplHeader,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt,
);
let gen_params_use_to_rbox = totrait_def.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt_rbox,
);
let uto_params_use = totrait_def.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt_erasedptr,
);
let trait_interface_use = totrait_def.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::NoSelf),
&ctokens.ts_empty,
);
let gen_params_header_rref = totrait_def.generics_tokenizer(
InWhat::ImplHeader,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt_sub_lt,
);
let gen_params_use_to_rref = totrait_def.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt_rref,
);
let mut shared_docs = String::new();
let mut from_ptr_docs = String::new();
let mut from_value_docs = String::new();
let mut from_const_docs = String::new();
if doc_hidden_attr.is_none() {
shared_docs = "\
<br><br>\
`can_it_downcast` describes whether the trait object can be \
converted back into the original type or not.<br>\n\
Its possible values are `TD_CanDowncast` and `TD_Opaque`.\n\
"
.to_string();
from_ptr_docs = format!(
"Constructs this trait object from a pointer to a type that implements `{trait_}`.\n\
\n\
This method is automatically generated,\n\
for more documentation you can look at\n\
[`abi_stable::docs::sabi_trait_inherent#from_ptr-method`]\n\
",
trait_ = trait_ident
);
from_value_docs = format!(
"Constructs this trait from a type that implements `{trait_}`.\n\
\n\
This method is automatically generated,\n\
for more documentation you can look at\n\
[`abi_stable::docs::sabi_trait_inherent#from_value-method`]\n\
",
trait_ = trait_ident
);
from_const_docs = format!(
"Constructs this trait from a constant of a type that implements `{trait_}`.\n\
\n\
This method is automatically generated,\n\
for more documentation you can look at\n\
[`abi_stable::docs::sabi_trait_inherent#from_const-method`]\n\
\n\
You can construct the `vtable_for` parameter with \
[`{make_vtable_ident}::VTABLE`].\n\
",
trait_ = trait_ident,
make_vtable_ident = make_vtable_ident,
);
}
let reborrow_methods = reborrow_methods_tokenizer(params);
let plus_lt = <_tokens.plus_lt;
let constructing_backend = match totrait_def.which_object {
WhichObject::DynTrait => quote!(
#trait_backend::from_const(
ptr,
can_it_downcast,
#make_vtable_ident::<#make_vtable_args_const>::VTABLE_INNER
)
),
WhichObject::RObject => quote!({
let _ = __sabi_re::ManuallyDrop::new(can_it_downcast);
#trait_backend::with_vtable_const::<_, Downcasting>(
ptr,
#make_vtable_ident::<#make_vtable_args_const>::VTABLE_INNER
)
}),
};
quote!(
impl<#gen_params_header> #trait_to<#gen_params_use_to>
where
_ErasedPtr: __sabi_re::AsPtr<PtrTarget = ()>,
{
#[doc=#from_ptr_docs]
#[doc=#shared_docs]
#submod_vis fn from_ptr<_OrigPtr,Downcasting>(
ptr:_OrigPtr,
can_it_downcast:Downcasting,
)->Self
where
_OrigPtr:
__sabi_re::CanTransmuteElement<(),TransmutedPtr=_ErasedPtr>,
_OrigPtr::PtrTarget:
#trait_ident<#trait_params #( #assoc_tys_a= #assoc_tys_b, )* >+
Sized
#plus_lt,
#trait_interface<#trait_interface_use>:
__sabi_re::GetRObjectVTable<
Downcasting,_OrigPtr::PtrTarget,_ErasedPtr,_OrigPtr
>,
#extra_constraints_ptr
{
let _can_it_downcast=can_it_downcast;
unsafe{
Self{
obj:#trait_backend::with_vtable::<_,#fn_can_it_downcast_arg>(
ptr,
#make_vtable_ident::<#make_vtable_args>::VTABLE_INNER
),
_marker:__sabi_re::UnsafeIgnoredType::DEFAULT,
}
}
}
#submod_vis fn from_sabi(obj:#trait_backend<#uto_params_use>)->Self{
Self{
obj,
_marker:__sabi_re::UnsafeIgnoredType::DEFAULT,
}
}
#reborrow_methods
}
impl<#gen_params_header_rbox> #trait_to<#gen_params_use_to_rbox> {
#[doc=#from_value_docs]
#[doc=#shared_docs]
#submod_vis fn from_value<_Self,Downcasting>(
ptr:_Self,
can_it_downcast:Downcasting,
)->Self
where
_Self:
#trait_ident<#trait_params #( #assoc_tys_c= #assoc_tys_d, )* >
#plus_lt,
#trait_interface<#trait_interface_use>:
__sabi_re::GetRObjectVTable<
Downcasting,_Self,__sabi_re::RBox<()>,__sabi_re::RBox<_Self>
>,
#extra_constraints_value
{
Self::from_ptr::<
__sabi_re::RBox<_Self>,
Downcasting
>(__sabi_re::RBox::new(ptr),can_it_downcast)
}
}
impl<#gen_params_header_rref> #trait_to<#gen_params_use_to_rref>{
#[doc=#from_const_docs]
#[doc=#shared_docs]
#submod_vis const fn from_const<_Self,Downcasting>(
ptr:&'_sub _Self,
can_it_downcast:Downcasting,
)->Self
where
_Self:
#trait_ident<#trait_params #( #assoc_tys_e = #assoc_tys_f, )* >
#plus_lt,
_Self: #one_lt
#trait_interface<#trait_interface_use>:
__sabi_re::GetRObjectVTable<
Downcasting, _Self, __sabi_re::RRef<'_sub, ()>, &'_sub _Self
>,
#extra_constraints_const
{
unsafe{
Self{
obj:#constructing_backend,
_marker:__sabi_re::UnsafeIgnoredType::DEFAULT,
}
}
}
}
)
.to_tokens(mod_);
}
fn reborrow_methods_tokenizer(
TokenizerParams {
totrait_def,
submod_vis,
trait_to,
lt_tokens,
..
}: TokenizerParams<'_>,
) -> impl ToTokens + '_ {
ToTokenFnMut::new(move |ts| {
let traits = totrait_def.trait_flags;
if traits.sync != traits.send {
return;
}
let gen_params_use_ref = totrait_def.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt_rref,
);
let gen_params_use_mut = totrait_def.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt_rmut,
);
quote!(
#submod_vis fn sabi_reborrow<'_sub>(&'_sub self)->#trait_to<#gen_params_use_ref> {
let x = self.obj.reborrow();
let x = unsafe{ __sabi_re::transmute(x) };
#trait_to::from_sabi(x)
}
#submod_vis fn sabi_reborrow_mut<'_sub>(&'_sub mut self)->#trait_to<#gen_params_use_mut>
where
_ErasedPtr: __sabi_re::AsMutPtr<PtrTarget=()>
{
let x = self.obj.reborrow_mut();
let x = unsafe{ __sabi_re::transmute(x) };
#trait_to::from_sabi(x)
}
)
.to_tokens(ts);
})
}
fn trait_and_impl(
TokenizerParams {
ctokens,
submod_vis,
trait_def,
trait_to,
lt_tokens,
trait_ident,
..
}: TokenizerParams,
mod_: &mut TokenStream2,
) {
let other_attrs = trait_def.other_attrs;
let gen_params_trait =
trait_def.generics_tokenizer(InWhat::ItemDecl, WithAssocTys::No, &ctokens.empty_ts);
let where_preds = (&trait_def.where_preds).into_iter();
let where_preds_b = where_preds.clone();
let methods_tokenizer_def = trait_def.methods_tokenizer(WhichItem::Trait);
let methods_tokenizer_impl = trait_def.methods_tokenizer(WhichItem::TraitImpl);
let lifetime_bounds_a = trait_def.lifetime_bounds.iter();
let lifetime_bounds_c = trait_def.lifetime_bounds.iter();
let super_traits_a = trait_def.impld_traits.iter().map(|t| &t.bound);
let super_traits_b = super_traits_a.clone();
let assoc_tys_a = trait_def.assoc_tys.values().map(|x| &x.assoc_ty);
let unsafety = trait_def.item.unsafety;
let erased_ptr_bounds = trait_def.erased_ptr_preds();
quote!(
#[allow(clippy::needless_lifetimes, clippy::new_ret_no_self)]
#( #other_attrs )*
#submod_vis #unsafety trait #trait_ident<
#gen_params_trait
>: #( #super_traits_a + )* #( #lifetime_bounds_a + )*
where
#(#where_preds,)*
{
#( #assoc_tys_a )*
#methods_tokenizer_def
}
)
.to_tokens(mod_);
let gen_params_use_trait =
trait_def.generics_tokenizer(InWhat::ItemUse, WithAssocTys::No, &ctokens.empty_ts);
if !trait_def.disable_trait_impl {
let gen_params_header = trait_def.generics_tokenizer(
InWhat::ImplHeader,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt_erasedptr,
);
let gen_params_use_to = trait_def.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt_erasedptr,
);
let assoc_ty_named_a = trait_def.assoc_tys.values().map(|x| &x.assoc_ty.ident);
let assoc_ty_named_b = assoc_ty_named_a.clone();
quote!(
#[deny(unsafe_op_in_unsafe_fn)]
#[allow(
clippy::needless_lifetimes,
clippy::new_ret_no_self,
)]
impl<#gen_params_header> #trait_ident<#gen_params_use_trait>
for #trait_to<#gen_params_use_to>
where
Self:#( #super_traits_b + )* #(#lifetime_bounds_c+)* ,
#erased_ptr_bounds
#(#where_preds_b,)*
{
#( type #assoc_ty_named_a=#assoc_ty_named_b; )*
#methods_tokenizer_impl
}
)
.to_tokens(mod_);
}
}
fn methods_impls(param: TokenizerParams, mod_: &mut TokenStream2) -> Result<(), syn::Error> {
let TokenizerParams {
totrait_def,
trait_to,
ctokens,
lt_tokens,
..
} = param;
let impl_where_preds = totrait_def.trait_impl_where_preds()?;
let super_traits_a = totrait_def.impld_traits.iter().map(|t| &t.bound);
let gen_params_header = totrait_def.generics_tokenizer(
InWhat::ImplHeader,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt_erasedptr,
);
let gen_params_use_to = totrait_def.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::NoSelf),
<_tokens.lt_erasedptr,
);
let generics_use1 = totrait_def.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::NoSelf),
&ctokens.ts_unit_erasedptr,
);
let methods_tokenizer_def = totrait_def.methods_tokenizer(WhichItem::TraitObjectImpl);
quote!(
#[allow(clippy::needless_lifetimes, clippy::new_ret_no_self)]
impl<#gen_params_header> #trait_to<#gen_params_use_to>
where
_ErasedPtr: __sabi_re::AsPtr<PtrTarget = ()>,
Self:#( #super_traits_a + )* ,
#impl_where_preds
{
#[inline]
fn sabi_vtable(
&self
)-> VTable_Ref<#generics_use1> {
unsafe{
VTable_Ref(self.obj.sabi_et_vtable())
}
}
#methods_tokenizer_def
}
)
.to_tokens(mod_);
Ok(())
}
fn declare_vtable(
TokenizerParams {
ctokens,
vtable_trait_decl,
submod_vis,
trait_interface,
..
}: TokenizerParams,
mod_: &mut TokenStream2,
) {
let generics_decl = vtable_trait_decl.generics_tokenizer(
InWhat::ItemDecl,
WithAssocTys::Yes(WhichSelf::NoSelf),
&ctokens.ts_self_erasedptr,
);
let mut generics_decl_unbounded = generics_decl;
generics_decl_unbounded.set_no_bounds();
let mut generics_use0 = vtable_trait_decl.generics_tokenizer(
InWhat::DummyStruct,
WithAssocTys::Yes(WhichSelf::NoSelf),
&ctokens.ts_self_erasedptr,
);
generics_use0.set_no_bounds();
let derive_attrs = vtable_trait_decl.derive_attrs;
let methods_tokenizer = vtable_trait_decl.methods_tokenizer(WhichItem::VtableDecl);
let lifetime_bounds = if vtable_trait_decl.lifetime_bounds.is_empty() {
None
} else {
let mut lifetime_bounds = quote!(_Self:);
for lt in &vtable_trait_decl.lifetime_bounds {
lifetime_bounds.append_all(quote!(#lt +));
}
lifetime_bounds.append(parse_str_as_ident("Sized"));
Some(lifetime_bounds)
}
.into_iter();
let trait_interface_use = vtable_trait_decl.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::NoSelf),
&ctokens.ts_empty,
);
let robject_vtable = quote!(
__sabi_re::RObjectVtable_Ref<
_Self,
_ErasedPtr,
#trait_interface<#trait_interface_use>
>
);
quote!(
#[repr(C)]
#[derive(abi_stable::StableAbi)]
#[sabi(kind(Prefix(prefix_ref = VTable_Ref)))]
#[sabi(missing_field(panic))]
#( #[sabi(prefix_bound(#lifetime_bounds))] )*
#[sabi(bound(#robject_vtable: ::abi_stable::StableAbi))]
#(#derive_attrs)*
#[doc(hidden)]
#submod_vis struct VTable<#generics_decl>
where
_ErasedPtr:__GetPointerKind,
{
_sabi_tys: __sabi_re::NonOwningPhantom<(#generics_use0)>,
_sabi_vtable:#robject_vtable,
#methods_tokenizer
}
)
.to_tokens(mod_);
}
fn vtable_impl(
TokenizerParams {
ctokens,
vtable_trait_impl,
trait_interface,
trait_ident,
make_vtable_ident,
lt_tokens,
..
}: TokenizerParams,
mod_: &mut TokenStream2,
) {
let struct_decl_generics = vtable_trait_impl.generics_tokenizer(
InWhat::ItemDecl,
WithAssocTys::No,
&ctokens.ts_getvtable_params,
);
let dummy_struct_tys = vtable_trait_impl.generics_tokenizer(
InWhat::DummyStruct,
WithAssocTys::No,
&ctokens.ts_getvtable_dummy_struct_fields,
);
let impl_header_generics = vtable_trait_impl.generics_tokenizer(
InWhat::ImplHeader,
WithAssocTys::No,
&ctokens.ts_getvtable_params,
);
let makevtable_generics = vtable_trait_impl.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::No,
&ctokens.ts_getvtable_params,
);
let trait_generics =
vtable_trait_impl.generics_tokenizer(InWhat::ItemUse, WithAssocTys::No, &ctokens.empty_ts);
let withmetadata_generics = vtable_trait_impl.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::Underscore),
&ctokens.ts_self_erasedptr,
);
let trait_interface_use = vtable_trait_impl.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::Underscore),
&ctokens.ts_empty,
);
let method_names_a = vtable_trait_impl.methods.iter().map(|m| m.name);
let method_names_b = method_names_a.clone();
let vtable_generics = vtable_trait_impl.generics_tokenizer(
InWhat::ItemUse,
WithAssocTys::Yes(WhichSelf::Underscore),
&ctokens.ts_unit_erasedptr,
);
let methods_tokenizer = vtable_trait_impl.methods_tokenizer(WhichItem::VtableImpl);
let one_lt = <_tokens.one_lt;
let extra_constraints = match vtable_trait_impl.which_object {
WhichObject::DynTrait => quote!(
#trait_interface<#trait_interface_use>:
::abi_stable::erased_types::InterfaceType,
__sabi_re::DynTraitVTable_Ref<
#one_lt
_ErasedPtr,
#trait_interface<#trait_interface_use>,
>:
__sabi_re::MakeDynTraitVTable<
#one_lt
_Self,
_OrigPtr,
IA,
>,
),
WhichObject::RObject => quote!(),
};
quote!(
struct #make_vtable_ident<#struct_decl_generics>(#dummy_struct_tys);
#[deny(unsafe_op_in_unsafe_fn)]
impl<#impl_header_generics> #make_vtable_ident<#makevtable_generics>
where
_Self: #trait_ident<#trait_generics>,
_OrigPtr:
__sabi_re::CanTransmuteElement<(), PtrTarget = _Self, TransmutedPtr = _ErasedPtr>,
_ErasedPtr:__sabi_re::AsPtr<PtrTarget=()>,
#trait_interface<#trait_interface_use>:
__sabi_re::GetRObjectVTable<IA,_Self,_ErasedPtr,_OrigPtr>,
#extra_constraints
{
const TMP0: __sabi_re::WithMetadata<
VTable<#withmetadata_generics>
>={
__sabi_re::WithMetadata::new(
VTable{
_sabi_tys: __sabi_re::NonOwningPhantom::NEW,
_sabi_vtable:__sabi_re::GetRObjectVTable::ROBJECT_VTABLE,
#(
#method_names_a:Self::#method_names_b,
)*
}
)
};
const VTABLE_INNER: __sabi_re::PrefixRef<VTable_Prefix<#vtable_generics> > =unsafe{
__sabi_re::WithMetadata::raw_as_prefix(&Self::TMP0)
.cast() };
#methods_tokenizer
}
)
.to_tokens(mod_);
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum SelfParam<'a> {
ByRef {
lifetime: Option<&'a syn::Lifetime>,
is_mutable: bool,
},
ByVal,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum WhichItem {
Trait,
TraitImpl,
TraitObjectImpl,
VtableDecl,
VtableImpl,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum WhichObject {
DynTrait,
RObject,
}
impl Default for WhichObject {
fn default() -> Self {
WhichObject::RObject
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum WhichSelf {
#[allow(dead_code)]
Regular,
Underscore,
#[allow(dead_code)]
FullyQualified,
NoSelf,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum WithAssocTys {
No,
Yes(WhichSelf),
}