765 lines
31 KiB
Rust
765 lines
31 KiB
Rust
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
// See Notices.txt for copyright information
|
|
use crate::{
|
|
value_derive_common::{
|
|
append_field, derive_clone_hash_eq_partialeq_for_struct, get_target, make_connect_impl,
|
|
Bounds, Builder, FieldsKind, ParsedField, ValueDeriveGenerics,
|
|
},
|
|
Errors, HdlAttr,
|
|
};
|
|
use proc_macro2::TokenStream;
|
|
use quote::{format_ident, quote, quote_spanned, ToTokens};
|
|
use syn::{
|
|
parse_quote, parse_quote_spanned, spanned::Spanned, FieldMutability, Generics, Ident,
|
|
ItemStruct, Member, Path, Token, Visibility,
|
|
};
|
|
|
|
crate::options! {
|
|
#[options = StructOptions]
|
|
pub(crate) enum StructOption {
|
|
OutlineGenerated(outline_generated),
|
|
FixedType(fixed_type),
|
|
ConnectInexact(connect_inexact),
|
|
Bounds(where_, Bounds),
|
|
Target(target, Path),
|
|
}
|
|
}
|
|
|
|
crate::options! {
|
|
#[options = FieldOptions]
|
|
pub(crate) enum FieldOption {
|
|
Flip(flip),
|
|
Skip(skip),
|
|
}
|
|
}
|
|
|
|
pub(crate) struct ParsedStructNames<I, S> {
|
|
pub(crate) ident: Ident,
|
|
pub(crate) type_struct_debug_ident: S,
|
|
pub(crate) type_struct_ident: Ident,
|
|
pub(crate) match_variant_ident: I,
|
|
pub(crate) builder_struct_ident: I,
|
|
pub(crate) mask_match_variant_ident: I,
|
|
pub(crate) mask_type_ident: I,
|
|
pub(crate) mask_type_debug_ident: S,
|
|
pub(crate) mask_value_ident: I,
|
|
pub(crate) mask_value_debug_ident: S,
|
|
pub(crate) mask_builder_struct_ident: I,
|
|
}
|
|
|
|
pub(crate) struct ParsedStruct {
|
|
pub(crate) options: HdlAttr<StructOptions>,
|
|
pub(crate) vis: Visibility,
|
|
pub(crate) struct_token: Token![struct],
|
|
pub(crate) generics: Generics,
|
|
pub(crate) fields_kind: FieldsKind,
|
|
pub(crate) fields: Vec<ParsedField<FieldOptions>>,
|
|
pub(crate) semi_token: Option<Token![;]>,
|
|
pub(crate) skip_check_fields: bool,
|
|
pub(crate) names: ParsedStructNames<Option<Ident>, Option<String>>,
|
|
}
|
|
|
|
impl ParsedStruct {
|
|
pub(crate) fn parse(item: &mut ItemStruct) -> syn::Result<Self> {
|
|
let ItemStruct {
|
|
attrs,
|
|
vis,
|
|
struct_token,
|
|
ident,
|
|
generics,
|
|
fields,
|
|
semi_token,
|
|
} = item;
|
|
let mut errors = Errors::new();
|
|
let struct_options = errors
|
|
.unwrap_or_default(HdlAttr::parse_and_take_attr(attrs))
|
|
.unwrap_or_default();
|
|
let (fields_kind, fields) = ParsedField::parse_fields(&mut errors, fields, false);
|
|
errors.finish()?;
|
|
Ok(ParsedStruct {
|
|
options: struct_options,
|
|
vis: vis.clone(),
|
|
struct_token: *struct_token,
|
|
generics: generics.clone(),
|
|
fields_kind,
|
|
fields,
|
|
semi_token: *semi_token,
|
|
skip_check_fields: false,
|
|
names: ParsedStructNames {
|
|
ident: ident.clone(),
|
|
type_struct_debug_ident: None,
|
|
type_struct_ident: format_ident!("__{}__Type", ident),
|
|
match_variant_ident: None,
|
|
builder_struct_ident: None,
|
|
mask_match_variant_ident: None,
|
|
mask_type_ident: None,
|
|
mask_type_debug_ident: None,
|
|
mask_value_ident: None,
|
|
mask_value_debug_ident: None,
|
|
mask_builder_struct_ident: None,
|
|
},
|
|
})
|
|
}
|
|
pub(crate) fn write_body(
|
|
&self,
|
|
target: Path,
|
|
names: ParsedStructNames<&Ident, &String>,
|
|
is_for_mask: bool,
|
|
tokens: &mut TokenStream,
|
|
) {
|
|
let Self {
|
|
options,
|
|
vis,
|
|
struct_token,
|
|
generics,
|
|
fields_kind,
|
|
fields,
|
|
semi_token,
|
|
skip_check_fields,
|
|
names: _,
|
|
} = self;
|
|
let skip_check_fields = *skip_check_fields || is_for_mask;
|
|
let ParsedStructNames {
|
|
ident: struct_ident,
|
|
type_struct_debug_ident,
|
|
type_struct_ident,
|
|
match_variant_ident,
|
|
builder_struct_ident,
|
|
mask_match_variant_ident: _,
|
|
mask_type_ident,
|
|
mask_type_debug_ident: _,
|
|
mask_value_ident,
|
|
mask_value_debug_ident,
|
|
mask_builder_struct_ident: _,
|
|
} = names;
|
|
let StructOptions {
|
|
outline_generated: _,
|
|
where_,
|
|
target: _,
|
|
fixed_type,
|
|
connect_inexact,
|
|
} = &options.body;
|
|
let ValueDeriveGenerics {
|
|
generics,
|
|
fixed_type_generics,
|
|
} = ValueDeriveGenerics::get(generics.clone(), where_);
|
|
let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
|
|
let unskipped_fields = fields
|
|
.iter()
|
|
.filter(|field| field.options.body.skip.is_none());
|
|
let _field_names = Vec::from_iter(fields.iter().map(|field| field.name.clone()));
|
|
let unskipped_field_names =
|
|
Vec::from_iter(unskipped_fields.clone().map(|field| field.name.clone()));
|
|
let unskipped_field_name_strs = Vec::from_iter(
|
|
unskipped_field_names
|
|
.iter()
|
|
.map(|field_name| field_name.to_token_stream().to_string()),
|
|
);
|
|
let unskipped_field_vars = Vec::from_iter(
|
|
unskipped_field_names
|
|
.iter()
|
|
.map(|field_name| format_ident!("__v_{}", field_name)),
|
|
);
|
|
let unskipped_field_flips = Vec::from_iter(
|
|
unskipped_fields
|
|
.clone()
|
|
.map(|field| field.options.body.flip.is_some()),
|
|
);
|
|
let mut any_fields_skipped = false;
|
|
let type_fields = Vec::from_iter(fields.iter().filter_map(|field| {
|
|
let ParsedField {
|
|
options,
|
|
vis,
|
|
name,
|
|
ty,
|
|
} = field;
|
|
let FieldOptions { flip: _, skip } = &options.body;
|
|
if skip.is_some() {
|
|
any_fields_skipped = true;
|
|
return None;
|
|
}
|
|
let ty = if is_for_mask {
|
|
parse_quote! { ::fayalite::ty::AsMask<#ty> }
|
|
} else {
|
|
ty.to_token_stream()
|
|
};
|
|
Some(syn::Field {
|
|
attrs: vec![],
|
|
vis: vis.clone(),
|
|
mutability: FieldMutability::None,
|
|
ident: match name.clone() {
|
|
Member::Named(name) => Some(name),
|
|
Member::Unnamed(_) => None,
|
|
},
|
|
colon_token: None,
|
|
ty: parse_quote! { <#ty as ::fayalite::expr::ToExpr>::Type },
|
|
})
|
|
}));
|
|
let field_types = Vec::from_iter(type_fields.iter().map(|field| field.ty.clone()));
|
|
let match_variant_fields = Vec::from_iter(fields.iter().zip(&type_fields).map(
|
|
|(parsed_field, type_field)| {
|
|
let field_ty = &parsed_field.ty;
|
|
syn::Field {
|
|
ty: parse_quote! { ::fayalite::expr::Expr<#field_ty> },
|
|
..type_field.clone()
|
|
}
|
|
},
|
|
));
|
|
|
|
let mask_value_fields = Vec::from_iter(fields.iter().zip(&type_fields).map(
|
|
|(parsed_field, type_field)| {
|
|
let field_ty = &parsed_field.ty;
|
|
syn::Field {
|
|
ty: parse_quote! { ::fayalite::ty::AsMask<#field_ty> },
|
|
..type_field.clone()
|
|
}
|
|
},
|
|
));
|
|
|
|
let mut type_struct_fields = fields_kind.into_fields(type_fields);
|
|
let mut match_variant_fields = fields_kind.into_fields(match_variant_fields);
|
|
let mut mask_value_fields = fields_kind.into_fields(mask_value_fields);
|
|
let phantom_data_field_name = any_fields_skipped.then(|| {
|
|
let phantom_data_field_name = Ident::new("__phantom_data", type_struct_ident.span());
|
|
let member = append_field(
|
|
&mut type_struct_fields,
|
|
syn::Field {
|
|
attrs: vec![],
|
|
vis: vis.clone(),
|
|
mutability: FieldMutability::None,
|
|
ident: Some(phantom_data_field_name.clone()),
|
|
colon_token: None,
|
|
ty: parse_quote_spanned! {type_struct_ident.span()=>
|
|
::fayalite::__std::marker::PhantomData<#struct_ident #type_generics>
|
|
},
|
|
},
|
|
);
|
|
append_field(
|
|
&mut match_variant_fields,
|
|
syn::Field {
|
|
attrs: vec![],
|
|
vis: Visibility::Inherited,
|
|
mutability: FieldMutability::None,
|
|
ident: Some(phantom_data_field_name.clone()),
|
|
colon_token: None,
|
|
ty: parse_quote_spanned! {type_struct_ident.span()=>
|
|
::fayalite::__std::marker::PhantomData<#struct_ident #type_generics>
|
|
},
|
|
},
|
|
);
|
|
append_field(
|
|
&mut mask_value_fields,
|
|
syn::Field {
|
|
attrs: vec![],
|
|
vis: Visibility::Inherited,
|
|
mutability: FieldMutability::None,
|
|
ident: Some(phantom_data_field_name),
|
|
colon_token: None,
|
|
ty: parse_quote_spanned! {type_struct_ident.span()=>
|
|
::fayalite::__std::marker::PhantomData<#struct_ident #type_generics>
|
|
},
|
|
},
|
|
);
|
|
member
|
|
});
|
|
let phantom_data_field_name_slice = phantom_data_field_name.as_slice();
|
|
let type_struct = ItemStruct {
|
|
attrs: vec![parse_quote! {#[allow(non_camel_case_types)]}],
|
|
vis: vis.clone(),
|
|
struct_token: *struct_token,
|
|
ident: type_struct_ident.clone(),
|
|
generics: generics.clone(),
|
|
fields: type_struct_fields,
|
|
semi_token: *semi_token,
|
|
};
|
|
type_struct.to_tokens(tokens);
|
|
let match_variant_struct = ItemStruct {
|
|
attrs: vec![parse_quote! {#[allow(non_camel_case_types)]}],
|
|
vis: vis.clone(),
|
|
struct_token: *struct_token,
|
|
ident: match_variant_ident.clone(),
|
|
generics: generics.clone(),
|
|
fields: match_variant_fields,
|
|
semi_token: *semi_token,
|
|
};
|
|
match_variant_struct.to_tokens(tokens);
|
|
let mask_type_body = if is_for_mask {
|
|
quote! {
|
|
::fayalite::__std::clone::Clone::clone(self)
|
|
}
|
|
} else {
|
|
let mask_value_struct = ItemStruct {
|
|
attrs: vec![parse_quote! {#[allow(non_camel_case_types)]}],
|
|
vis: vis.clone(),
|
|
struct_token: *struct_token,
|
|
ident: mask_value_ident.clone(),
|
|
generics: generics.clone(),
|
|
fields: mask_value_fields,
|
|
semi_token: *semi_token,
|
|
};
|
|
mask_value_struct.to_tokens(tokens);
|
|
let debug_mask_value_body = match fields_kind {
|
|
FieldsKind::Unit => quote! {
|
|
f.debug_struct(#mask_value_debug_ident).finish()
|
|
},
|
|
FieldsKind::Named(_) => quote! {
|
|
f.debug_struct(#mask_value_debug_ident)
|
|
#(.field(#unskipped_field_name_strs, &self.#unskipped_field_names))*
|
|
.finish()
|
|
},
|
|
FieldsKind::Unnamed(_) => quote! {
|
|
f.debug_tuple(#mask_value_debug_ident)
|
|
#(.field(&self.#unskipped_field_names))*
|
|
.finish()
|
|
},
|
|
};
|
|
quote! {
|
|
#[automatically_derived]
|
|
impl #impl_generics ::fayalite::__std::fmt::Debug
|
|
for #mask_value_ident #type_generics
|
|
#where_clause
|
|
{
|
|
fn fmt(
|
|
&self,
|
|
f: &mut ::fayalite::__std::fmt::Formatter<'_>,
|
|
) -> ::fayalite::__std::fmt::Result {
|
|
#debug_mask_value_body
|
|
}
|
|
}
|
|
}
|
|
.to_tokens(tokens);
|
|
quote! {
|
|
#mask_type_ident {
|
|
#(#unskipped_field_names:
|
|
::fayalite::ty::Type::mask_type(&self.#unskipped_field_names),)*
|
|
#(#phantom_data_field_name_slice: ::fayalite::__std::marker::PhantomData,)*
|
|
}
|
|
}
|
|
};
|
|
let debug_type_body = match fields_kind {
|
|
FieldsKind::Unit => quote! {
|
|
f.debug_struct(#type_struct_debug_ident).finish()
|
|
},
|
|
FieldsKind::Named(_) => quote! {
|
|
f.debug_struct(#type_struct_debug_ident)
|
|
#(.field(#unskipped_field_name_strs, &self.#unskipped_field_names))*
|
|
.finish()
|
|
},
|
|
FieldsKind::Unnamed(_) => quote! {
|
|
f.debug_tuple(#type_struct_debug_ident)
|
|
#(.field(&self.#unskipped_field_names))*
|
|
.finish()
|
|
},
|
|
};
|
|
for the_struct_ident in [&type_struct_ident, match_variant_ident]
|
|
.into_iter()
|
|
.chain(is_for_mask.then_some(mask_value_ident))
|
|
{
|
|
derive_clone_hash_eq_partialeq_for_struct(
|
|
the_struct_ident,
|
|
&generics,
|
|
&Vec::from_iter(
|
|
unskipped_field_names
|
|
.iter()
|
|
.cloned()
|
|
.chain(phantom_data_field_name.clone()),
|
|
),
|
|
)
|
|
.to_tokens(tokens);
|
|
}
|
|
let check_v = format_ident!("__v");
|
|
let field_checks = Vec::from_iter(fields.iter().map(|ParsedField { ty, name, .. }| {
|
|
quote_spanned! {ty.span()=>
|
|
__check_field(#check_v.#name);
|
|
}
|
|
}));
|
|
if fixed_type.is_some() {
|
|
let (impl_generics, type_generics, where_clause) = fixed_type_generics.split_for_impl();
|
|
quote! {
|
|
#[automatically_derived]
|
|
impl #impl_generics ::fayalite::ty::FixedType for #type_struct_ident #type_generics
|
|
#where_clause
|
|
{
|
|
fn fixed_type() -> Self {
|
|
Self {
|
|
#(#unskipped_field_names: ::fayalite::ty::FixedType::fixed_type(),)*
|
|
#(#phantom_data_field_name_slice:
|
|
::fayalite::__std::marker::PhantomData,)*
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.to_tokens(tokens);
|
|
}
|
|
if !skip_check_fields {
|
|
quote! {
|
|
fn __check_field<T: ::fayalite::ty::Value>(_v: T)
|
|
where
|
|
<T as ::fayalite::expr::ToExpr>::Type: ::fayalite::ty::Type<Value = T>,
|
|
{}
|
|
fn __check_fields #impl_generics(#check_v: #target #type_generics)
|
|
#where_clause
|
|
{
|
|
#(#field_checks)*
|
|
}
|
|
}
|
|
.to_tokens(tokens);
|
|
}
|
|
let mut builder = Builder::new(builder_struct_ident.clone(), vis.clone());
|
|
for field in unskipped_fields.clone() {
|
|
builder.insert_field(
|
|
field.name.clone(),
|
|
|v| {
|
|
parse_quote_spanned! {v.span()=>
|
|
::fayalite::expr::ToExpr::to_expr(&#v)
|
|
}
|
|
},
|
|
|t| {
|
|
parse_quote_spanned! {t.span()=>
|
|
::fayalite::expr::Expr<<
|
|
<#t as ::fayalite::expr::ToExpr>::Type
|
|
as ::fayalite::ty::Type
|
|
>::Value>
|
|
}
|
|
},
|
|
|t| {
|
|
parse_quote_spanned! {t.span()=>
|
|
where
|
|
#t: ::fayalite::expr::ToExpr,
|
|
}
|
|
},
|
|
);
|
|
}
|
|
let builder = builder.finish_filling_in_fields();
|
|
builder.to_tokens(tokens);
|
|
let build_type_fields =
|
|
Vec::from_iter(unskipped_fields.clone().map(|ParsedField { name, .. }| {
|
|
let builder_field_name = &builder.get_field(name).unwrap().1.builder_field_name;
|
|
quote_spanned! {struct_ident.span()=>
|
|
#name: ::fayalite::expr::ToExpr::ty(&#builder_field_name)
|
|
}
|
|
}));
|
|
let build_expr_fields =
|
|
Vec::from_iter(unskipped_fields.clone().map(|ParsedField { name, .. }| {
|
|
let builder_field_name = &builder.get_field(name).unwrap().1.builder_field_name;
|
|
quote_spanned! {struct_ident.span()=>
|
|
#builder_field_name.to_canonical_dyn()
|
|
}
|
|
}));
|
|
let build_specified_fields = unskipped_fields.clone().map(
|
|
|ParsedField {
|
|
options: _,
|
|
vis: _,
|
|
name,
|
|
ty,
|
|
}| {
|
|
let ty = if is_for_mask {
|
|
parse_quote_spanned! {name.span()=>
|
|
::fayalite::expr::Expr<::fayalite::ty::AsMask<#ty>>
|
|
}
|
|
} else {
|
|
parse_quote_spanned! {name.span()=>
|
|
::fayalite::expr::Expr<#ty>
|
|
}
|
|
};
|
|
(name.clone(), ty)
|
|
},
|
|
);
|
|
let build_body = parse_quote_spanned! {struct_ident.span()=>
|
|
{
|
|
::fayalite::expr::ToExpr::to_expr(
|
|
&::fayalite::expr::ops::BundleLiteral::new_unchecked(
|
|
::fayalite::intern::Intern::intern(&[#(
|
|
#build_expr_fields,
|
|
)*][..]),
|
|
#type_struct_ident {
|
|
#(#build_type_fields,)*
|
|
#(#phantom_data_field_name_slice:
|
|
::fayalite::__std::marker::PhantomData,)*
|
|
},
|
|
),
|
|
)
|
|
}
|
|
};
|
|
builder
|
|
.make_build_method(
|
|
&Ident::new("build", struct_ident.span()),
|
|
build_specified_fields,
|
|
&generics,
|
|
&parse_quote_spanned! {struct_ident.span()=>
|
|
#type_struct_ident #type_generics
|
|
},
|
|
&parse_quote_spanned! {struct_ident.span()=>
|
|
::fayalite::expr::Expr<#target #type_generics>
|
|
},
|
|
build_body,
|
|
)
|
|
.to_tokens(tokens);
|
|
make_connect_impl(
|
|
*connect_inexact,
|
|
&generics,
|
|
&type_struct_ident,
|
|
unskipped_fields.clone().map(|field| {
|
|
let ty = &field.ty;
|
|
parse_quote_spanned! {field.name.span()=>
|
|
<#ty as ::fayalite::expr::ToExpr>::Type
|
|
}
|
|
}),
|
|
)
|
|
.to_tokens(tokens);
|
|
let empty_builder_ty = builder.ty([], Some(&parse_quote! { Self }), false);
|
|
quote! {
|
|
#[automatically_derived]
|
|
impl #impl_generics ::fayalite::__std::fmt::Debug for #type_struct_ident #type_generics
|
|
#where_clause
|
|
{
|
|
fn fmt(
|
|
&self,
|
|
f: &mut ::fayalite::__std::fmt::Formatter<'_>,
|
|
) -> ::fayalite::__std::fmt::Result {
|
|
#debug_type_body
|
|
}
|
|
}
|
|
|
|
#[automatically_derived]
|
|
impl #impl_generics ::fayalite::ty::Type for #type_struct_ident #type_generics
|
|
#where_clause
|
|
{
|
|
type CanonicalType = ::fayalite::bundle::DynBundleType;
|
|
type Value = #target #type_generics;
|
|
type CanonicalValue = ::fayalite::bundle::DynBundle;
|
|
type MaskType = #mask_type_ident #type_generics;
|
|
type MaskValue = #mask_value_ident #type_generics;
|
|
type MatchVariant = #match_variant_ident #type_generics;
|
|
type MatchActiveScope = ();
|
|
type MatchVariantAndInactiveScope = ::fayalite::ty::MatchVariantWithoutScope<
|
|
#match_variant_ident #type_generics,
|
|
>;
|
|
type MatchVariantsIter = ::fayalite::__std::iter::Once<
|
|
<Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
|
|
>;
|
|
#[allow(unused_variables)]
|
|
fn match_variants<IO: ::fayalite::bundle::BundleValue>(
|
|
this: ::fayalite::expr::Expr<<Self as ::fayalite::ty::Type>::Value>,
|
|
module_builder: &mut ::fayalite::module::ModuleBuilder<
|
|
IO,
|
|
::fayalite::module::NormalModule,
|
|
>,
|
|
source_location: ::fayalite::source_location::SourceLocation,
|
|
) -> <Self as ::fayalite::ty::Type>::MatchVariantsIter
|
|
where
|
|
<IO as ::fayalite::expr::ToExpr>::Type:
|
|
::fayalite::bundle::BundleType<Value = IO>,
|
|
{
|
|
::fayalite::__std::iter::once(::fayalite::ty::MatchVariantWithoutScope(
|
|
#match_variant_ident {
|
|
#(#unskipped_field_names: this.field(#unskipped_field_name_strs),)*
|
|
#(#phantom_data_field_name_slice:
|
|
::fayalite::__std::marker::PhantomData,)*
|
|
},
|
|
))
|
|
}
|
|
fn mask_type(&self) -> <Self as ::fayalite::ty::Type>::MaskType {
|
|
#mask_type_body
|
|
}
|
|
fn canonical(&self) -> <Self as ::fayalite::ty::Type>::CanonicalType {
|
|
let fields = ::fayalite::bundle::BundleType::fields(self);
|
|
::fayalite::bundle::DynBundleType::new(fields)
|
|
}
|
|
fn source_location(&self) -> ::fayalite::source_location::SourceLocation {
|
|
::fayalite::source_location::SourceLocation::caller()
|
|
}
|
|
fn type_enum(&self) -> ::fayalite::ty::TypeEnum {
|
|
::fayalite::ty::TypeEnum::BundleType(::fayalite::ty::Type::canonical(self))
|
|
}
|
|
fn from_canonical_type(t: <Self as ::fayalite::ty::Type>::CanonicalType) -> Self {
|
|
let [#(#unskipped_field_vars),*] = *::fayalite::bundle::BundleType::fields(&t)
|
|
else {
|
|
::fayalite::__std::panic!("wrong number of fields");
|
|
};
|
|
Self {
|
|
#(#unskipped_field_names: #unskipped_field_vars.from_canonical_type_helper(
|
|
#unskipped_field_name_strs,
|
|
#unskipped_field_flips,
|
|
),)*
|
|
#(#phantom_data_field_name_slice: ::fayalite::__std::marker::PhantomData,)*
|
|
}
|
|
}
|
|
}
|
|
|
|
#[automatically_derived]
|
|
impl #impl_generics ::fayalite::ty::TypeWithDeref for #type_struct_ident #type_generics
|
|
#where_clause
|
|
{
|
|
#[allow(unused_variables)]
|
|
fn expr_deref(this: &::fayalite::expr::Expr<<Self as ::fayalite::ty::Type>::Value>)
|
|
-> &<Self as ::fayalite::ty::Type>::MatchVariant
|
|
{
|
|
::fayalite::intern::Interned::<_>::into_inner(
|
|
::fayalite::intern::Intern::intern_sized(#match_variant_ident {
|
|
#(#unskipped_field_names: this.field(#unskipped_field_name_strs),)*
|
|
#(#phantom_data_field_name_slice:
|
|
::fayalite::__std::marker::PhantomData,)*
|
|
}),
|
|
)
|
|
}
|
|
}
|
|
|
|
#[automatically_derived]
|
|
impl #impl_generics ::fayalite::bundle::BundleType for #type_struct_ident #type_generics
|
|
#where_clause
|
|
{
|
|
type Builder = #empty_builder_ty;
|
|
fn builder() -> <Self as ::fayalite::bundle::BundleType>::Builder {
|
|
#empty_builder_ty::new()
|
|
}
|
|
fn fields(&self) -> ::fayalite::intern::Interned<
|
|
[::fayalite::bundle::FieldType<::fayalite::intern::Interned<
|
|
dyn ::fayalite::ty::DynCanonicalType,
|
|
>>],
|
|
>
|
|
{
|
|
::fayalite::intern::Intern::intern(&[#(
|
|
::fayalite::bundle::FieldType {
|
|
name: ::fayalite::intern::Intern::intern(#unskipped_field_name_strs),
|
|
flipped: #unskipped_field_flips,
|
|
ty: ::fayalite::ty::DynType::canonical_dyn(
|
|
&self.#unskipped_field_names,
|
|
),
|
|
},
|
|
)*][..])
|
|
}
|
|
fn fields_hint() -> ::fayalite::bundle::FieldsHint {
|
|
::fayalite::bundle::FieldsHint::new([#(
|
|
::fayalite::bundle::FieldType {
|
|
name: ::fayalite::intern::Intern::intern(#unskipped_field_name_strs),
|
|
flipped: #unskipped_field_flips,
|
|
ty: ::fayalite::bundle::TypeHint::<#field_types>::intern_dyn(),
|
|
},
|
|
)*], false)
|
|
}
|
|
}
|
|
|
|
#[automatically_derived]
|
|
impl #impl_generics ::fayalite::expr::ToExpr for #target #type_generics
|
|
#where_clause
|
|
{
|
|
type Type = #type_struct_ident #type_generics;
|
|
fn ty(&self) -> <Self as ::fayalite::expr::ToExpr>::Type {
|
|
#type_struct_ident {
|
|
#(#unskipped_field_names: ::fayalite::expr::ToExpr::ty(
|
|
&self.#unskipped_field_names,
|
|
),)*
|
|
#(#phantom_data_field_name_slice: ::fayalite::__std::marker::PhantomData,)*
|
|
}
|
|
}
|
|
fn to_expr(&self) -> ::fayalite::expr::Expr<Self> {
|
|
::fayalite::expr::Expr::from_value(self)
|
|
}
|
|
}
|
|
|
|
#[automatically_derived]
|
|
impl #impl_generics ::fayalite::ty::Value for #target #type_generics
|
|
#where_clause
|
|
{
|
|
fn to_canonical(&self) -> <
|
|
<Self as ::fayalite::expr::ToExpr>::Type
|
|
as ::fayalite::ty::Type
|
|
>::CanonicalValue
|
|
{
|
|
let ty = ::fayalite::ty::Type::canonical(&::fayalite::expr::ToExpr::ty(self));
|
|
::fayalite::bundle::DynBundle::new(ty, ::fayalite::__std::sync::Arc::new([
|
|
#(::fayalite::ty::DynValueTrait::to_canonical_dyn(
|
|
&self.#unskipped_field_names,
|
|
),)*
|
|
]))
|
|
}
|
|
}
|
|
|
|
#[automatically_derived]
|
|
impl #impl_generics ::fayalite::bundle::BundleValue for #target #type_generics
|
|
#where_clause
|
|
{
|
|
}
|
|
}
|
|
.to_tokens(tokens);
|
|
}
|
|
}
|
|
|
|
impl ToTokens for ParsedStruct {
|
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
|
let ParsedStructNames {
|
|
ident: struct_ident,
|
|
type_struct_debug_ident,
|
|
type_struct_ident,
|
|
match_variant_ident,
|
|
builder_struct_ident,
|
|
mask_match_variant_ident,
|
|
mask_type_ident,
|
|
mask_type_debug_ident,
|
|
mask_value_ident,
|
|
mask_value_debug_ident,
|
|
mask_builder_struct_ident,
|
|
} = &self.names;
|
|
macro_rules! unwrap_or_set {
|
|
($(let $var:ident =? $fallback_value:expr;)*) => {
|
|
$(let $var = $var.clone().unwrap_or_else(|| $fallback_value);)*
|
|
};
|
|
}
|
|
unwrap_or_set! {
|
|
let type_struct_debug_ident =? format!("{struct_ident}::Type");
|
|
let match_variant_ident =? format_ident!("__{}__MatchVariant", struct_ident);
|
|
let builder_struct_ident =? format_ident!("__{}__Builder", struct_ident);
|
|
let mask_match_variant_ident =? format_ident!("__AsMask__{}__MatchVariant", struct_ident);
|
|
let mask_type_ident =? format_ident!("__AsMask__{}__Type", struct_ident);
|
|
let mask_type_debug_ident =? format!("AsMask<{struct_ident}>::Type");
|
|
let mask_value_ident =? format_ident!("__AsMask__{}", struct_ident);
|
|
let mask_value_debug_ident =? format!("AsMask<{struct_ident}>");
|
|
let mask_builder_struct_ident =? format_ident!("__AsMask__{}__Builder", struct_ident);
|
|
}
|
|
let target = get_target(&self.options.body.target, struct_ident);
|
|
let names = ParsedStructNames {
|
|
ident: struct_ident.clone(),
|
|
type_struct_debug_ident: &type_struct_debug_ident,
|
|
type_struct_ident: type_struct_ident.clone(),
|
|
match_variant_ident: &match_variant_ident,
|
|
builder_struct_ident: &builder_struct_ident,
|
|
mask_match_variant_ident: &mask_match_variant_ident,
|
|
mask_type_ident: &mask_type_ident,
|
|
mask_type_debug_ident: &mask_type_debug_ident,
|
|
mask_value_ident: &mask_value_ident,
|
|
mask_value_debug_ident: &mask_value_debug_ident,
|
|
mask_builder_struct_ident: &mask_builder_struct_ident,
|
|
};
|
|
self.write_body(target, names, false, tokens);
|
|
let mask_names = ParsedStructNames {
|
|
ident: mask_value_ident.clone(),
|
|
type_struct_debug_ident: &mask_type_debug_ident,
|
|
type_struct_ident: mask_type_ident.clone(),
|
|
match_variant_ident: &mask_match_variant_ident,
|
|
builder_struct_ident: &mask_builder_struct_ident,
|
|
mask_match_variant_ident: &mask_match_variant_ident,
|
|
mask_type_ident: &mask_type_ident,
|
|
mask_type_debug_ident: &mask_type_debug_ident,
|
|
mask_value_ident: &mask_value_ident,
|
|
mask_value_debug_ident: &mask_value_debug_ident,
|
|
mask_builder_struct_ident: &mask_builder_struct_ident,
|
|
};
|
|
self.write_body(mask_value_ident.clone().into(), mask_names, true, tokens);
|
|
}
|
|
}
|
|
|
|
pub(crate) fn value_derive_struct(mut item: ItemStruct) -> syn::Result<TokenStream> {
|
|
let item = ParsedStruct::parse(&mut item)?;
|
|
let outline_generated = item.options.body.outline_generated;
|
|
let mut contents = quote! {
|
|
const _: () = {
|
|
#item
|
|
};
|
|
};
|
|
if outline_generated.is_some() {
|
|
contents = crate::outline_generated(contents, "value-struct-");
|
|
}
|
|
Ok(contents)
|
|
}
|