refactor: restructure code

This commit is contained in:
Kristofers Solo 2025-09-13 14:12:42 +03:00
parent f8527d60e7
commit f18bbc7fdd
Signed by: kristoferssolo
GPG Key ID: 8687F2D3EEE6F0ED
4 changed files with 37 additions and 39 deletions

View File

@ -15,7 +15,7 @@ pub struct Field {
pub attrs: Vec<Attribute>,
pub vis: TokenStream,
pub name: Ident,
pub ty: Ident,
pub ty: TokenStream,
}
#[derive(Debug)]
@ -53,7 +53,7 @@ impl From<grammar::Field> for Field {
.collect(),
vis: value.vis.to_token_stream(),
name: value.name,
ty: value.ty,
ty: value.ty.to_token_stream(),
}
}
}

View File

@ -6,29 +6,29 @@ pub fn generate_impl(info: &Struct) -> Result<TokenStream> {
let name = &info.name;
let vis = &info.vis;
let generics = &info.generics;
let file_ident = format_ident!("{name}File");
let file_ident = format_ident!("{}File", name.to_string());
let mut file_fields = Vec::new();
let mut assignments = Vec::new();
for field in &info.fields {
let name = &field.name;
let ty = &field.ty;
let vis = &field.vis;
let fname = &field.name;
let fty = &field.ty;
let fvis = &field.vis;
let default_override = parse_from_file_default_attr(&field.attrs)?;
let shadow_ty = quote! { <#ty as filecaster::FromFile>::Shadow };
file_fields.push(quote! { #vis #name: Option<#shadow_ty> });
let shadow_ty = quote! { <#fty as ::filecaster::FromFile>::Shadow };
file_fields.push(quote! { #fvis #fname: Option<#shadow_ty> });
if let Some(expr) = default_override {
assignments.push(quote! {
#name: file.#name
.map(|inner| <#ty as filecaster::FromFile>::from_file(Some(inner)))
.unwrap_or(#expr.into())
#fname: file.#fname
.map(|inner| <#fty as ::filecaster::FromFile>::from_file(Some(inner)))
.unwrap_or_else(|| (#expr).into())
});
} else {
assignments.push(quote! {
#name: <#ty as filecaster::FromFile>::from_file(file.#name)
#fname: <#fty as ::filecaster::FromFile>::from_file(file.#fname)
});
}
}
@ -41,7 +41,7 @@ pub fn generate_impl(info: &Struct) -> Result<TokenStream> {
#(#file_fields),*
}
impl #generics filecaster::FromFile for #name #generics {
impl #generics ::filecaster::FromFile for #name #generics {
type Shadow = #file_ident #generics;
fn from_file(file: Option<Self::Shadow>) -> Self {
@ -54,32 +54,24 @@ pub fn generate_impl(info: &Struct) -> Result<TokenStream> {
impl #generics From<Option<#file_ident #generics>> for #name #generics {
fn from(value: Option<#file_ident #generics>) -> Self {
<Self as filecaster::FromFile>::from_file(value)
<Self as ::filecaster::FromFile>::from_file(value)
}
}
impl #generics From<#file_ident #generics> for #name #generics {
fn from(value: #file_ident #generics) -> Self {
<Self as filecaster::FromFile>::from_file(Some(value))
<Self as ::filecaster::FromFile>::from_file(Some(value))
}
}
})
}
fn build_derive_clause() -> TokenStream {
let mut traits = vec![quote! { Debug }, quote! { Clone }, quote! { Default }];
#[cfg(feature = "serde")]
{
traits.push(quote! { serde::Deserialize });
traits.push(quote! { serde::Serialize });
quote! {
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(::serde::Deserialize, ::serde::Serialize))]
#[cfg_attr(feature = "merge", derive(::merge::Merge))]
}
#[cfg(feature = "merge")]
{
traits.push(quote! { merge::Merge });
}
quote! { #[derive( #(#traits),* )] }
}
#[cfg(test)]

View File

@ -12,7 +12,6 @@ pub struct Foo {
}
*/
unsynn! {
pub struct Attribute {
pub path: Ident, // attr
pub tokens: ParenthesisGroupContaining<TokenStream> // "value"

View File

@ -4,7 +4,7 @@ use unsynn::*;
pub fn parse_from_file_default_attr(attrs: &[Attribute]) -> Result<Option<TokenStream>> {
for attr in attrs {
if attr.path == "from_file" {
if attr.path.tokens_to_string().trim() == "from_file" {
let tokens = attr.tokens.clone();
let iter = tokens.clone().into_token_iter();
@ -21,16 +21,22 @@ pub fn parse_from_file_default_attr(attrs: &[Attribute]) -> Result<Option<TokenS
fn extract_default_token(token: TokenStream) -> Option<TokenStream> {
let mut iter = token.into_token_iter().peekable();
while let Some(TokenTree::Ident(id)) = iter.next() {
if id != "default" {
continue;
}
match iter.next() {
Some(TokenTree::Punct(eq)) if eq.as_char() == '=' => {
return Some(collect_until_commas(&mut iter));
while let Some(tt) = iter.next() {
match &tt {
TokenTree::Ident(id) if id == "default" => {
// accept optional whitespace/punct and then '='
// next non-whitespace token should be '='
if let Some(next) = iter.peek()
&& let TokenTree::Punct(p) = next
&& p.as_char() == '='
{
iter.next();
return Some(collect_until_commas(&mut iter));
}
// if we see "default" without '=', treat as parse failure
return None;
}
_ => return None,
_ => continue,
}
}
@ -48,7 +54,8 @@ where
iter.next();
break;
}
expr.extend(once(iter.next().unwrap()));
// peek returned Some, so unwrap is safe
expr.extend(once(iter.next().expect("this should be impossible to see")));
}
expr
}