fayalite/crates/fayalite-proc-macros-impl/src/value_derive_struct.rs

710 lines
30 KiB
Rust
Raw Normal View History

2024-06-11 06:09:13 +00:00
// 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)
}