use proc_macro2::TokenStream;
use super::{BUILDER_BUILD_MUST_USE, BUILDER_MUST_USE, EmitContext};
use crate::model::*;
use crate::util::*;
pub fn emit_main(ctx: &EmitContext<'_>) -> TokenStream {
let EmitContext {
target,
target_deprecated,
builder,
builder_vis,
unchecked_builder,
unchecked_builder_vis,
impl_generics,
ty_generics,
struct_generics,
where_clause,
fields,
..
} = ctx;
let t_true = simple_ident("true");
let builder_doc = format!("A builder type for [`{target}`].");
let field_generics1 = fields.gen_names();
let field_generics2 = fields.gen_names();
let field_generics3 = fields.gen_names();
let build_gens = fields
.pub_api()
.map(|f| f.default.is_some().then_some(&f.gen_name));
let build_params = build_gens.clone().flatten();
let build_args = build_gens.map(|f| f.unwrap_or(&t_true));
quote::quote! {
#[doc = #builder_doc]
#[repr(transparent)]
#[must_use = #BUILDER_MUST_USE]
#target_deprecated
#builder_vis struct #builder <
#struct_generics #( const #field_generics1: ::core::primitive::bool = false ),*
>
#where_clause
{
inner: #unchecked_builder < #ty_generics >,
_unsafe: (),
}
impl < #impl_generics > #builder < #ty_generics > #where_clause {
#[inline]
pub const fn new() -> Self {
unsafe { #unchecked_builder::new().assert_init() }
}
}
impl < #impl_generics #( const #field_generics2: ::core::primitive::bool ),* >
#builder < #ty_generics #(#field_generics3),* >
#where_clause
{
#[inline]
#unchecked_builder_vis const fn into_unchecked(self) -> #unchecked_builder < #ty_generics > {
let this = ::core::mem::ManuallyDrop::new(self);
let this = &raw const this as *const Self;
unsafe { ::core::ptr::read(&raw const (*this).inner) }
}
}
impl < #impl_generics #( const #build_params: ::core::primitive::bool ),* >
#builder < #ty_generics #(#build_args),* >
#where_clause
{
#[must_use = #BUILDER_BUILD_MUST_USE]
#[inline]
pub const fn build(self) -> #target < #ty_generics > {
unsafe {
self.into_unchecked().build()
}
}
}
}
}
pub fn emit_builder_fn(ctx: &EmitContext<'_>) -> TokenStream {
let EmitContext {
target,
builder,
builder_vis,
builder_fn,
impl_generics,
ty_generics,
where_clause,
..
} = ctx;
let Some(builder_fn) = builder_fn else {
return TokenStream::new();
};
quote::quote! {
impl < #impl_generics > #target < #ty_generics > #where_clause {
#[inline]
#builder_vis const fn #builder_fn() -> #builder < #ty_generics > {
#builder::new()
}
}
}
}