fack_codegen/
structure.rs1use alloc::{format, vec::Vec};
4use proc_macro2::TokenStream;
5use syn::{FieldsNamed, FieldsUnnamed, Generics, Ident, Type};
6
7use super::common::{FieldRef, Format, ImportRoot, InlineOptions, Transparent};
8
9#[derive(Clone, Debug, PartialEq, Eq, Hash)]
11pub struct Structure {
12 pub inline_opts: Option<InlineOptions>,
14
15 pub root_import: Option<ImportRoot>,
17
18 pub name_ident: Ident,
20
21 pub generics: Generics,
23
24 pub field_list: FieldList,
26
27 pub options: StructureOptions,
29}
30
31#[derive(Clone, Debug, PartialEq, Eq, Hash)]
33pub enum StructureOptions {
34 Standalone {
36 source_field: Option<FieldRef>,
38
39 format_args: Format,
41 },
42
43 Transparent(Transparent),
45
46 Forward {
48 source_field: Option<FieldRef>,
50
51 field_ref: FieldRef,
53
54 field_type: Type,
56
57 format_args: Format,
59 },
60}
61
62#[derive(Debug, Clone, PartialEq, Eq, Hash)]
64pub enum FieldList {
65 Named(Vec<NamedField>),
67
68 Unnamed(Vec<UnnamedField>),
70
71 Unit,
73}
74
75impl FieldList {
76 #[inline]
78 pub fn raw(fields: &syn::Fields) -> syn::Result<Self> {
79 match fields {
80 syn::Fields::Named(FieldsNamed { named, .. }) => {
81 let field_list = named
82 .iter()
83 .map(|syn::Field { ident, ty, .. }| {
84 let name = ident
85 .clone()
86 .ok_or_else(|| syn::Error::new_spanned(ident, "expected a named field"))?;
87
88 let ty = ty.clone();
89
90 Ok(NamedField { name, ty })
91 })
92 .collect::<syn::Result<Vec<_>>>()?;
93
94 Ok(FieldList::Named(field_list))
95 }
96 syn::Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
97 let field_list = unnamed
98 .iter()
99 .map(|syn::Field { ty, .. }| {
100 let ty = ty.clone();
101
102 Ok(UnnamedField { ty })
103 })
104 .collect::<syn::Result<Vec<_>>>()?;
105
106 Ok(FieldList::Unnamed(field_list))
107 }
108 syn::Fields::Unit => Ok(FieldList::Unit),
109 }
110 }
111
112 pub fn exactly_one(fields: &syn::Fields) -> syn::Result<(FieldRef, Type)> {
114 const DEFAULT_FIELD: usize = 0;
115
116 match fields {
117 syn::Fields::Named(FieldsNamed { named, .. }) => {
118 if named.len() != 1 {
119 return Err(syn::Error::new_spanned(fields, "expected exactly one field"));
120 }
121
122 let field = &named[DEFAULT_FIELD];
123
124 let name = field.ident.clone();
125
126 let ty = field.ty.clone();
127
128 Ok((name.map(FieldRef::Named).unwrap_or(FieldRef::Indexed(DEFAULT_FIELD)), ty))
129 }
130 syn::Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
131 if unnamed.len() != 1 {
132 return Err(syn::Error::new_spanned(fields, "expected exactly one field"));
133 }
134
135 let field = &unnamed[DEFAULT_FIELD];
136
137 let ty = field.ty.clone();
138
139 Ok((FieldRef::Indexed(DEFAULT_FIELD), ty))
140 }
141 syn::Fields::Unit => Err(syn::Error::new_spanned(fields, "expected at least one field")),
142 }
143 }
144
145 pub fn pattern(&self) -> syn::Result<TokenStream> {
147 match self {
148 FieldList::Named(named) => {
149 let pattern = named.iter().map(|field| {
150 let name = &field.name;
151
152 quote::quote! { #name }
153 });
154
155 Ok(quote::quote! { { #(#pattern),* } })
156 }
157 FieldList::Unnamed(unnamed) => {
158 let pattern = unnamed.iter().enumerate().map(|(index, _)| {
159 let ident = Ident::new(&format!("_{}", index), proc_macro2::Span::call_site());
160
161 quote::quote! { #ident }
162 });
163
164 Ok(quote::quote! { ( #(#pattern),* ) })
165 }
166 FieldList::Unit => Ok(quote::quote! {}),
167 }
168 }
169}
170
171#[derive(Debug, Clone, PartialEq, Eq, Hash)]
173pub struct NamedField {
174 name: Ident,
176
177 ty: Type,
179}
180
181#[derive(Debug, Clone, PartialEq, Eq, Hash)]
183pub struct UnnamedField {
184 ty: Type,
186}