use quote::format_ident;
use std::collections::HashMap;
use syn::{
AngleBracketedGenericArguments, Arm, AttrStyle, Attribute, Block, Expr, ExprAsync, ExprAwait,
ExprBlock, ExprCall, ExprField, ExprIf, ExprLet, ExprMatch, ExprMethodCall, ExprPath,
ExprReference, ExprReturn, ExprTuple, Field, Fields, FieldsNamed, GenericArgument, Generics,
Ident, ImplItem, ItemStruct, LitStr, Local, LocalInit, Member, Pat, PatIdent, PatTuple,
PatTupleStruct, Path, PathArguments, PathSegment, PredicateType, QSelf, Stmt, TraitBound,
TraitBoundModifier, Type, TypeInfer, TypeParam, TypeParamBound, TypePath, TypeReference,
Visibility, WherePredicate,
ext::IdentExt,
punctuated::Punctuated,
token::{As, Comma, PathSep, Plus, Pub, Semi, Struct},
};
use crate::{
acceptor::common::{
ast::{
acceptor_spec::StructAcceptorSpec,
accepts_trait_ast::{
Accepts, AcceptsEnum, AcceptsGenerics, AcceptsT, AsyncAccepts,
PartialAcceptsTraitImpl,
},
},
function::generate::{
accepts_path, codegen_acceptor_path, generate_accept_expr_maybe_await,
},
},
common::{
collection::HybridDeck,
context::CodegenContext,
function::{
generate::{
AccessMode, crate_common_error_path_with_segment, option_match_expr,
phantom_data_path, result_err_path, result_match_expr, result_ok_path,
self_field_access_expr,
},
generate_doc_attr, generate_drop_expr_call,
},
syn::{
ast::{
function::{NewFnOptions, generate_getter_method, generate_new_impl_fn},
partial_impl::PartialInherentImpl,
},
ext::{
AngleBracketedGenericArgumentsConstructExt, ArmConstructExt, AttributeConstructExt,
BlockConstructExt, ExprAsyncConstructExt, ExprAwaitConstructExt,
ExprBlockConstructExt, ExprCallConstructExt, ExprFieldConstructExt,
ExprIfConstructExt, ExprLetConstructExt, ExprMatchConstructExt,
ExprMethodCallConstructExt, ExprPathConstructExt, ExprReferenceConstructExt,
ExprReturnConstructExt, ExprTupleConstructExt, FieldConstructExt, FieldsExt,
FieldsNamedConstructExt, IdentConstructExt, ItemStructConstructExt,
LitStrConstructExt, LocalConstructExt, LocalInitConstructExt, PatIdentConstructExt,
PatTupleConstructExt, PatTupleStructConstructExt, PathConstructExt,
PathSegmentConstructExt, PredicateTypeConstructExt, PunctuatedConstructExt,
QSelfConstructExt, TraitBoundConstructExt, TypeInferConstructExt,
TypeParamConstructExt, TypePathConstructExt, TypeReferenceConstructExt,
},
},
},
};
use super::{
config::{AcceptsImplsConfig, ForwardSource},
spec::LinearAcceptorSpec,
};
pub fn build_linear_accepts_spec(
ctx: &CodegenContext,
spec: &LinearAcceptorSpec,
) -> syn::Result<StructAcceptorSpec<AcceptsEnum, 1, 0, 0>> {
let mut struct_accepts_spec = {
let mut struct_ = ItemStruct::from_parts(
spec.attrs.clone(),
spec.vis.clone(),
Struct::default(),
spec.ident.clone(),
Generics::default(),
Fields::Named(FieldsNamed::from_named(Punctuated::new())),
None,
);
struct_.attrs.push(generate_doc_attr(LitStr::from_value(
"Generated by `generate_linear_acceptor` macro.",
)));
let inherent_impls = HybridDeck::from_inline([PartialInherentImpl::default()]);
let accepts_traits = HybridDeck::from_inline([]);
let trait_impls = HybridDeck::from_inline([]);
StructAcceptorSpec::from_parts(struct_, inherent_impls, accepts_traits, trait_impls)
};
let phantom_types = Punctuated::<Type, Comma>::new();
build_generics(ctx, &mut struct_accepts_spec, spec);
let has_phantom_types = !phantom_types.is_empty();
build_fields(&mut struct_accepts_spec, spec, &phantom_types)?;
build_inherent_impl(&mut struct_accepts_spec, spec, has_phantom_types)?;
build_handler_mode(ctx, &mut struct_accepts_spec, spec);
Ok(struct_accepts_spec)
}
fn build_generics(
ctx: &CodegenContext,
struct_spec: &mut StructAcceptorSpec<AcceptsEnum, 1, 0, 0>,
spec: &LinearAcceptorSpec,
) {
let generics = &mut struct_spec.struct_.generics;
generics
.params
.push(syn::GenericParam::Type(spec.accepts_value_param.clone()));
if let Some(next) = &spec.next {
add_generic_with_accepts_bounds(
ctx,
generics,
next.generics_ident.clone(),
next.accepts_ty.clone(),
&spec.accept_impls,
);
}
if let Some(handler_error) = &spec.handler.handler_error {
add_generic_with_accepts_bounds(
ctx,
generics,
handler_error.generics_ident.clone(),
handler_error.context_ty.clone(),
&spec.accept_impls,
);
}
if let Some(guard_access_error) = spec
.handler
.mut_guard
.as_ref()
.and_then(|guard| guard.guard_error.as_ref())
{
let accepts_ident = guard_access_error.generics_ident.clone();
let error_ty = guard_access_error.error_ty.clone();
match guard_access_error.forward_source {
ForwardSource::None => {
add_generic_with_accepts_bounds(
ctx,
generics,
accepts_ident,
error_ty,
&spec.accept_impls,
);
}
ForwardSource::Clone => {
let source_ty = spec.handler.source_ty.clone();
let guard_path = crate_common_error_path_with_segment(
ctx,
PathSegment::from_ident(format_ident!("GuardErrorWithSource")),
);
let context_ty: Type = syn::parse_quote!(#guard_path<#error_ty, #source_ty>);
add_generic_with_accepts_bounds(
ctx,
generics,
accepts_ident,
context_ty,
&spec.accept_impls,
);
}
ForwardSource::Ref => {
let source_ty = spec.handler.source_ty.clone();
let guard_path = crate_common_error_path_with_segment(
ctx,
PathSegment::from_ident(format_ident!("GuardErrorWithSource")),
);
let context_ty: Type = syn::parse_quote!(#guard_path<#error_ty, &'a #source_ty>);
generics
.params
.push(syn::GenericParam::Type(TypeParam::from_ident(
accepts_ident.clone(),
)));
let param_ty = Type::Path(TypePath::from_path(Path::from(accepts_ident)));
let where_clause = generics.make_where_clause();
let mut bounds = Punctuated::new();
if spec.accept_impls.is_sync() {
bounds.push(TypeParamBound::Trait(TraitBound::from_parts(
None,
TraitBoundModifier::None,
Some(syn::parse_quote!(for<'a>)),
accepts_path(ctx, Accepts, context_ty.clone()),
)));
}
if spec.accept_impls.is_async() {
bounds.push(TypeParamBound::Trait(TraitBound::from_parts(
None,
TraitBoundModifier::None,
Some(syn::parse_quote!(for<'a>)),
accepts_path(ctx, AsyncAccepts, context_ty),
)));
}
where_clause
.predicates
.push(WherePredicate::Type(PredicateType::from_bounds(
param_ty, bounds,
)));
}
}
}
}
fn add_generic_with_accepts_bounds(
ctx: &CodegenContext,
generics: &mut Generics,
ident: Ident,
accepts_ty: Type,
gen_accepts_type: &AcceptsImplsConfig,
) {
generics
.params
.push(syn::GenericParam::Type(TypeParam::from_ident(
ident.clone(),
)));
let param_ty = Type::Path(TypePath::from_path(Path::from(ident)));
let where_clause = generics.make_where_clause();
where_clause
.predicates
.push(WherePredicate::Type(PredicateType::from_bounds(
param_ty,
accepts_trait_bounds(ctx, accepts_ty, gen_accepts_type),
)));
}
fn accepts_trait_bounds(
ctx: &CodegenContext,
accepts_ty: Type,
gen_accepts_type: &AcceptsImplsConfig,
) -> Punctuated<TypeParamBound, Plus> {
let mut bounds = Punctuated::new();
if gen_accepts_type.is_sync() {
bounds.push(TypeParamBound::Trait(TraitBound::from_path(accepts_path(
ctx,
Accepts,
accepts_ty.clone(),
))));
}
if gen_accepts_type.is_async() {
bounds.push(TypeParamBound::Trait(TraitBound::from_path(accepts_path(
ctx,
AsyncAccepts,
accepts_ty,
))));
}
bounds
}
fn build_fields(
struct_spec: &mut StructAcceptorSpec<AcceptsEnum, 1, 0, 0>,
spec: &LinearAcceptorSpec,
phantom_types: &Punctuated<Type, Comma>,
) -> syn::Result<()> {
let named_fields = &mut struct_spec.struct_.fields.as_named_mut()?.named;
named_fields.push(Field::from_ident(
spec.handler.source_field_ident.clone(),
spec.handler.source_ty.clone(),
));
if let Some(next) = &spec.next {
named_fields.push(Field::from_ident(
next.field_ident.clone(),
next.field_ty.clone(),
));
}
if let Some(handler_error) = &spec.handler.handler_error {
named_fields.push(Field::from_ident(
handler_error.field_ident.clone(),
handler_error.field_ty.clone(),
));
}
if let Some(guard_access_error) = &spec
.handler
.mut_guard
.as_ref()
.and_then(|guard| guard.guard_error.as_ref())
{
named_fields.push(Field::from_ident(
guard_access_error.field_ident.clone(),
guard_access_error.field_ty.clone(),
));
}
if !phantom_types.is_empty() {
named_fields.push(Field::from_ident(
format_ident!("_marker"),
Type::Path(TypePath::from_path(phantom_data_path(
phantom_types.clone(),
))),
));
}
Ok(())
}
fn build_inherent_impl(
struct_spec: &mut StructAcceptorSpec<AcceptsEnum, 1, 0, 0>,
spec: &LinearAcceptorSpec,
has_phantom_types: bool,
) -> syn::Result<()> {
let impl_items = &mut struct_spec.inherent_impls.inline_mut()[0].items;
let field_ident = &spec.handler.source_field_ident;
impl_items.push(syn::ImplItem::Fn(generate_new_impl_fn(
struct_spec.struct_.fields.as_named()?,
&{
let mut auto_inits = HashMap::new();
if has_phantom_types {
auto_inits.insert(
format_ident!("_marker"),
Expr::Path(ExprPath::from_path(phantom_data_path(Punctuated::new()))),
);
}
auto_inits
},
NewFnOptions::default(),
)));
impl_items.push(ImplItem::Fn(generate_getter_method(
vec![generate_doc_attr(LitStr::from_value(
format!("Returns a reference to the `{}` field.", field_ident).as_str(),
))],
Visibility::Public(Pub::default()),
field_ident.clone(),
field_ident.clone(),
spec.handler.source_ty.clone(),
true,
false,
)));
if let Some(next) = &spec.next {
let field_ty = next.field_ty.clone();
let field_ident = next.field_ident.clone();
impl_items.push(ImplItem::Fn(generate_getter_method(
vec![generate_doc_attr(LitStr::from_value(
format!("Returns a reference to the `{}` field.", field_ident).as_str(),
))],
Visibility::Public(Pub::default()),
field_ident.clone(),
field_ident.clone(),
field_ty.clone(),
true,
false,
)));
impl_items.push(ImplItem::Fn(generate_getter_method(
vec![generate_doc_attr(LitStr::from_value(
format!(
"Returns a mutable reference to the `{}` field.",
field_ident
)
.as_str(),
))],
Visibility::Public(Pub::default()),
format_ident!("{}{}", field_ident.unraw(), "_mut"),
field_ident.clone(),
field_ty,
true,
true,
)));
}
if let Some(handler_error) = &spec.handler.handler_error {
let field_ty = handler_error.field_ty.clone();
let field_ident = handler_error.field_ident.clone();
impl_items.push(ImplItem::Fn(generate_getter_method(
vec![generate_doc_attr(LitStr::from_value(
format!("Returns a reference to the `{}` field.", field_ident).as_str(),
))],
Visibility::Public(Pub::default()),
field_ident.clone(),
field_ident.clone(),
field_ty.clone(),
true,
false,
)));
impl_items.push(ImplItem::Fn(generate_getter_method(
vec![generate_doc_attr(LitStr::from_value(
format!(
"Returns a mutable reference to the `{}` field.",
field_ident
)
.as_str(),
))],
Visibility::Public(Pub::default()),
format_ident!("{}{}", field_ident.unraw(), "_mut"),
field_ident,
field_ty,
true,
true,
)));
}
if let Some(guard_access_error) = &spec
.handler
.mut_guard
.as_ref()
.and_then(|guard| guard.guard_error.as_ref())
{
let field_ty = guard_access_error.field_ty.clone();
let field_ident = guard_access_error.field_ident.clone();
impl_items.push(ImplItem::Fn(generate_getter_method(
vec![generate_doc_attr(LitStr::from_value(
format!("Returns a reference to the `{}` field.", field_ident).as_str(),
))],
Visibility::Public(Pub::default()),
field_ident.clone(),
field_ident.clone(),
field_ty.clone(),
true,
false,
)));
impl_items.push(ImplItem::Fn(generate_getter_method(
vec![generate_doc_attr(LitStr::from_value(
format!(
"Returns a mutable reference to the `{}` field.",
field_ident
)
.as_str(),
))],
Visibility::Public(Pub::default()),
format_ident!("{}{}", field_ident.unraw(), "_mut"),
field_ident.clone(),
field_ty,
true,
true,
)));
}
Ok(())
}
fn build_handler_mode(
ctx: &CodegenContext,
struct_spec: &mut StructAcceptorSpec<AcceptsEnum, 1, 0, 0>,
spec: &LinearAcceptorSpec,
) {
let generate_accept_block = |is_async: bool| {
let generate_receiver_local = {
let pat = Pat::Ident(PatIdent::mut_from_ident(format_ident!("receiver")));
let init_expr = if let Some(mut_guard) = &spec.handler.mut_guard {
let mut_guard_path = {
let mut mut_guard_path = codegen_acceptor_path(&ctx);
mut_guard_path
.segments
.push(PathSegment::from_ident(format_ident!("guard_access")));
mut_guard_path.segments.push(PathSegment {
ident: if is_async {
format_ident!("AsyncMutGuardAccess")
} else {
format_ident!("MutGuardAccess")
},
arguments: PathArguments::AngleBracketed(
AngleBracketedGenericArguments::from_args({
let mut trait_args = Punctuated::new();
trait_args
.push(GenericArgument::Type(mut_guard.guarded_ty.clone()));
trait_args.push(GenericArgument::Type(Type::Infer(
TypeInfer::new_default(),
)));
trait_args
}),
),
});
mut_guard_path
};
let mut match_expr = {
let func = Expr::Path({
let mut path = mut_guard_path.clone();
path.segments
.push(PathSegment::from_ident(format_ident!("acquire")));
let qself = QSelf::from_ty_position_as(
Box::new(Type::Path(TypePath::from_path(
mut_guard.guard_path.clone(),
))),
path.segments.len() - 1,
Some(As::default()),
);
ExprPath::from_qself_path(Some(qself), path)
});
let args = Punctuated::from_value(self_field_access_expr(
spec.handler.source_field_ident.clone(),
AccessMode::Ref,
));
Expr::Call(ExprCall::from_func_args(Box::new(func), args))
};
if is_async {
match_expr = Expr::Await(ExprAwait::from_base(Box::new(match_expr)));
}
Expr::Match(result_match_expr(
match_expr,
format_ident!("ok"),
Expr::Path(ExprPath::from_path(Path::from(format_ident!("ok")))),
format_ident!("err"),
Expr::Block(ExprBlock::from_block(Block::from_stmts({
let mut stmts = Vec::new();
if let Some(guard_error_spec) = mut_guard.guard_error.as_ref() {
let forward_source = &guard_error_spec.forward_source;
let error_expr: Expr = syn::parse_quote!(err.error);
let (guard_error_accepts_ty, value_expr) = match forward_source {
ForwardSource::None => {
(guard_error_spec.error_ty.clone(), error_expr)
}
ForwardSource::Clone | ForwardSource::Ref => {
let guard_path_args = {
let mut args = Punctuated::new();
args.push(GenericArgument::Type(
guard_error_spec.error_ty.clone(),
));
args.push(GenericArgument::Type(
if let ForwardSource::Ref = forward_source {
Type::Reference(TypeReference::from_elem(Box::new(
spec.handler.source_ty.clone(),
)))
} else {
spec.handler.source_ty.clone()
},
));
args
};
let guard_path = crate_common_error_path_with_segment(
ctx,
PathSegment::from_parts(
format_ident!("GuardErrorWithSource"),
PathArguments::AngleBracketed(
AngleBracketedGenericArguments::from_colon2_args(
Some(PathSep::default()),
guard_path_args,
),
),
),
);
let guard_new_path = {
let mut guard_new_path = guard_path.clone();
guard_new_path
.segments
.push(PathSegment::from_ident(format_ident!("new")));
guard_new_path
};
let value_expr_args = {
let mut args = Punctuated::new();
args.push(error_expr);
args.push(if let ForwardSource::Ref = forward_source {
self_field_access_expr(
Member::Named(
spec.handler.source_field_ident.clone(),
),
AccessMode::Ref,
)
} else {
let self_source_field = self_field_access_expr(
Member::Named(
spec.handler.source_field_ident.clone(),
),
AccessMode::Ref,
);
Expr::MethodCall(
ExprMethodCall::from_receiver_method_args(
Box::new(self_source_field),
format_ident!("clone"),
Punctuated::new(),
),
)
});
args
};
let value_expr = Expr::Call(ExprCall::from_func_args(
Box::new(Expr::Path(ExprPath::from_path(guard_new_path))),
value_expr_args,
));
(Type::Path(TypePath::from_path(guard_path)), value_expr)
}
};
stmts.push(Stmt::Expr(
generate_accept_expr_maybe_await(
ctx,
if !is_async {
AcceptsEnum::Sync(Accepts)
} else {
AcceptsEnum::Async(AsyncAccepts)
},
guard_error_accepts_ty,
Expr::Reference(ExprReference::from_expr(Box::new(
Expr::Field(ExprField::from_base_member(
Box::new(Expr::Path(ExprPath::from_path(Path::from(
format_ident!("self"),
)))),
Member::Named(guard_error_spec.field_ident.clone()),
)),
))),
value_expr,
),
Some(Semi::default()),
));
}
stmts.push(Stmt::Expr(
Expr::Match(option_match_expr(
None,
Expr::Field(ExprField::from_base_member(
Box::new(Expr::Path(ExprPath::from_path(Path::from(
format_ident!("err"),
)))),
Member::Named(format_ident!("guard")),
)),
Expr::Return(ExprReturn::new_none()),
format_ident!("guard"),
Expr::Path(ExprPath::from_path(Path::from(format_ident!("guard")))),
)),
None,
));
stmts
}))),
))
} else {
self_field_access_expr(
Member::Named(spec.handler.source_field_ident.clone()),
AccessMode::Ref,
)
};
Local::from_pat_init(pat, Some(LocalInit::from_expr(Box::new(init_expr))))
};
let generate_handler_apply_stmt = {
let handler_path = {
let mut handler_path = codegen_acceptor_path(ctx);
handler_path
.segments
.push(PathSegment::from_ident(format_ident!("handler")));
handler_path.segments.push({
let (handler_ident, args) = {
let mut string: String = String::new();
let mut args = Punctuated::new();
args.push(GenericArgument::Type(Type::Infer(TypeInfer::new_default())));
args.push(GenericArgument::Type(Type::Path(TypePath::from_path(
Path::from(spec.accepts_value_param.ident.clone()),
))));
if spec.next.is_some() {
string.push_str("Linear");
} else {
string.push_str("Final");
}
if is_async {
string.push_str("Async");
}
if spec.handler.handler_error.is_some() {
string.push_str("ValueError");
args.push(GenericArgument::Type(Type::Infer(TypeInfer::new_default())));
} else {
string.push_str("Value");
}
string.push_str("Handler");
if spec.handler.mut_guard.is_some() {
string.push_str("Mut");
} else {
string.push_str("Ref");
}
(Ident::from_str(&string), args)
};
PathSegment::from_parts(
handler_ident,
PathArguments::AngleBracketed(AngleBracketedGenericArguments::from_args(
args,
)),
)
});
handler_path
};
let mut handler_apply_expr = {
let func = Expr::Path({
let mut path = handler_path;
path.segments
.push(PathSegment::from_ident(format_ident!("apply")));
let qself = QSelf::from_ty_position_as(
Box::new(Type::Path(TypePath::from_path(
spec.handler.handler_path.clone(),
))),
path.segments.len() - 1,
Some(As::default()),
);
ExprPath::from_qself_path(Some(qself), path)
});
let args = {
let mut args = Punctuated::new();
args.push(Expr::Reference(if spec.handler.mut_guard.is_none() {
ExprReference::from_expr(Box::new(Expr::Field(
ExprField::from_base_member(
Box::new(Expr::Path(ExprPath::from_path(Path::from_segments(
Punctuated::from_value(PathSegment::from_ident(format_ident!(
"self",
))),
)))),
Member::Named(spec.handler.source_field_ident.clone()),
),
)))
} else {
ExprReference::mut_from_expr(Box::new(Expr::Path(ExprPath::from_path(
Path::from_segments(Punctuated::from_value(PathSegment::from_ident(
format_ident!("receiver"),
))),
))))
}));
args.push(Expr::Path(ExprPath::from_path(Path::from_segments(
Punctuated::from_value(PathSegment::from_ident(format_ident!("value",))),
))));
if let Some(next_spec) = &spec.next {
args.push(Expr::MethodCall(ExprMethodCall::from_receiver_method_args(
Box::new(Expr::Field(ExprField::from_base_member(
Box::new(Expr::Path(ExprPath::from_path(Path::from(
format_ident!("self"),
)))),
Member::Named(next_spec.field_ident.clone()),
))),
format_ident!("is_some"),
Punctuated::new(),
)));
}
args
};
Expr::Call(ExprCall::from_func_args(Box::new(func), args))
};
if is_async {
handler_apply_expr =
Expr::Await(ExprAwait::from_base(Box::new(handler_apply_expr)));
}
if let Some(handler_error) = &spec.handler.handler_error {
handler_apply_expr =
Expr::Match(ExprMatch::from_expr_arms(Box::new(handler_apply_expr), {
let mut arms = Vec::new();
arms.push(Arm::from_pat_guard_body(
Pat::TupleStruct(PatTupleStruct::from_path_elems(
result_ok_path(),
Punctuated::from_value(Pat::Ident(PatIdent::from_ident(
format_ident!("ok"),
))),
)),
None,
Box::new(Expr::Path(ExprPath::from_path(Path::from(format_ident!(
"ok"
))))),
));
arms.push(Arm::from_pat_guard_body(
Pat::TupleStruct(PatTupleStruct::from_path_elems(
result_err_path(),
Punctuated::from_value(Pat::Ident(PatIdent::from_ident(
format_ident!("err"),
))),
)),
None,
Box::new(Expr::Block(ExprBlock::from_block(Block::from_stmts({
let mut stmts = Vec::new();
stmts.push(Stmt::Expr(
generate_accept_expr_maybe_await(
ctx,
if !is_async {
AcceptsEnum::Sync(Accepts)
} else {
AcceptsEnum::Async(AsyncAccepts)
},
handler_error.context_ty.clone(),
Expr::Reference(ExprReference::from_expr(Box::new(
Expr::Field(ExprField::from_base_member(
Box::new(Expr::Path(ExprPath::from_path(
Path::from(format_ident!("self")),
))),
Member::Named(handler_error.field_ident.clone()),
)),
))),
Expr::Path(ExprPath::from_path(Path::from_segments(
Punctuated::from_value(PathSegment::from_ident(
format_ident!("err"),
)),
))),
),
Some(Semi::default()),
));
stmts.push(Stmt::Expr(
Expr::Return(ExprReturn::new_none()),
Some(Semi::default()),
));
stmts
})))),
));
arms
}));
}
let stmt = match spec.next.is_some() {
true => Stmt::Local(Local::from_pat_init(
Pat::Ident(PatIdent::from_ident(format_ident!("next_value"))),
Some(LocalInit::from_expr(Box::new(handler_apply_expr))),
)),
false => Stmt::Expr(handler_apply_expr, Some(Semi::default())),
};
stmt
};
let generate_next_accept_stmt = if let Some(next_accepts_config) = &spec.next {
let cond = Expr::Let(ExprLet::from_pat_expr(
Box::new(Pat::Tuple(PatTuple::from_elems({
let mut elems = Punctuated::new();
elems.push(Pat::TupleStruct(PatTupleStruct::from_path_elems(
Path::from(format_ident!("Some")),
Punctuated::from_value(Pat::Ident(PatIdent::from_ident(
next_accepts_config.field_ident.clone(),
))),
)));
elems.push(Pat::TupleStruct(PatTupleStruct::from_path_elems(
Path::from(format_ident!("Some")),
Punctuated::from_value(Pat::Ident(PatIdent::from_ident(format_ident!(
"next_value",
)))),
)));
elems
}))),
Box::new(Expr::Tuple(ExprTuple::from_elems({
let mut elems = Punctuated::new();
elems.push(Expr::Reference(ExprReference::from_expr(Box::new(
Expr::Field(ExprField::from_base_member(
Box::new(Expr::Path(ExprPath::from_path(Path::from(format_ident!(
"self",
))))),
Member::Named(next_accepts_config.field_ident.clone()),
)),
))));
elems.push(Expr::Path(ExprPath::from_path(Path::from(format_ident!(
"next_value",
)))));
elems
}))),
));
let accept_expr = generate_accept_expr_maybe_await(
ctx,
if !is_async {
AcceptsEnum::Sync(Accepts)
} else {
AcceptsEnum::Async(AsyncAccepts)
},
Type::Path(TypePath::from_path(Path::from(
spec.accepts_value_param.ident.clone(),
))),
Expr::Path(ExprPath::from_path(Path::from(
next_accepts_config.field_ident.clone(),
))),
Expr::Path(ExprPath::from_path(Path::from_segments(
Punctuated::from_value(PathSegment::from_ident(format_ident!("next_value",))),
))),
);
let expr = Expr::If(ExprIf::from_cond_then(
Box::new(cond),
Block::from_stmts(vec![Stmt::Expr(accept_expr, Some(Semi::default()))]),
));
Some(Stmt::Expr(expr, Some(Semi::default())))
} else {
None
};
let mut block_stmts = {
let mut stmts = Vec::new();
stmts.push(Stmt::Local(generate_receiver_local));
stmts.push(generate_handler_apply_stmt);
if spec.handler.mut_guard.is_none() {
stmts.push(Stmt::Expr(
Expr::Call(generate_drop_expr_call(Expr::Path(ExprPath::from_path(
Path::from_segments(Punctuated::from_value(PathSegment::from_ident(
format_ident!("receiver"),
))),
)))),
Some(Semi::default()),
));
}
if let Some(generate_next_accept_stmt) = generate_next_accept_stmt {
stmts.push(generate_next_accept_stmt);
}
stmts
};
if is_async {
block_stmts = vec![Stmt::Expr(
Expr::Async(ExprAsync::async_move_from_block(Block::from_stmts(
block_stmts,
))),
None,
)];
}
Block::from_stmts(block_stmts)
};
let accepts_traits_extras = struct_spec.accepts_trait_impls.extras_mut();
if let Some(sync_metas) = &spec.accept_impls.sync {
let mut accepts = PartialAcceptsTraitImpl::from_accepts(
AcceptsGenerics::default(),
AcceptsEnum::Sync(Accepts),
AcceptsT::Generics(spec.accepts_value_param.clone()),
generate_accept_block(false),
);
accepts.attrs.extend(
sync_metas
.iter()
.cloned()
.map(|meta| Attribute::from_style_meta(AttrStyle::Outer, meta)),
);
accepts_traits_extras.push(accepts);
}
if let Some(async_metas) = &spec.accept_impls.async_ {
let mut accepts = PartialAcceptsTraitImpl::from_accepts(
AcceptsGenerics::default(),
AcceptsEnum::Async(AsyncAccepts),
AcceptsT::Generics(spec.accepts_value_param.clone()),
generate_accept_block(true),
);
accepts.attrs.extend(
async_metas
.iter()
.cloned()
.map(|meta| Attribute::from_style_meta(AttrStyle::Outer, meta)),
);
accepts_traits_extras.push(accepts);
}
}