Repository: sxyazi/yazi
File: yazi-codegen/src/lib.rs (Rust)

Code before:
use proc_macro::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput, Fields, parse_macro_input};

#[proc_macro_derive(DeserializeOver)]
pub fn deserialize_over(input: TokenStream) -> TokenStream {
	let DeriveInput { ident, .. } = parse_macro_input!(input as DeriveInput);

	quote! {
		impl #ident {
			pub(crate) fn deserialize_over(self, input: &str) -> Result<Self, toml::de::Error> {
				crate::error_with_input(self.deserialize_over_with(crate::parse_recoverable(input)?), input)
			}
		}
	}
	.into()
}

#[proc_macro_derive(DeserializeOver1)]
pub fn deserialize_over1(input: TokenStream) -> TokenStream {
	let DeriveInput { ident, data, .. } = parse_macro_input!(input as DeriveInput);

	let assignments = match data {
		Data::Struct(struct_) => match struct_.fields {
			Fields::Named(fields) => {
				let mut assignments = Vec::with_capacity(fields.named.len());

				for field in fields.named {
					let field_ident = &field.ident;
					let field_name = field_ident.as_ref().unwrap().to_string();

					assignments.push(quote! {
						if let Some(value) = table.remove(#field_name) {
							let span = value.span();
							let table = match value.into_inner() {
								toml::de::DeValue::Table(table) => table,
								_ => return Err(serde::de::Error::custom(format!("expected top-level `{}` to be a TOML table", #field_name))),
							};

Review comment (suggestion):
The derive-generated `deserialize_over` method returns `Result<_, toml::de::Error>` using an unqualified `Result`. In modules that `use anyhow::Result`, this will not compile (anyhow::Result only takes one type parameter). Generate `::core::result::Result` (or fully qualify `std::result::Result`) in the macro expansion to avoid being shadowed by imports in the target crate.

Code after:
use proc_macro::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput, Fields, parse_macro_input};

#[proc_macro_derive(DeserializeOver)]
pub fn deserialize_over(input: TokenStream) -> TokenStream {
	let DeriveInput { ident, .. } = parse_macro_input!(input as DeriveInput);

	quote! {
		impl #ident {
			pub(crate) fn deserialize_over(self, input: &str) -> Result<Self, toml::de::Error> {
				crate::error_with_input(self.deserialize_over_with(toml::de::DeTable::parse(input)?), input)
			}
		}
	}
	.into()
}

#[proc_macro_derive(DeserializeOver1)]
pub fn deserialize_over1(input: TokenStream) -> TokenStream {
	let DeriveInput { ident, data, .. } = parse_macro_input!(input as DeriveInput);

	let assignments = match data {
		Data::Struct(struct_) => match struct_.fields {
			Fields::Named(fields) => {
				let mut assignments = Vec::with_capacity(fields.named.len());

				for field in fields.named {
					let field_ident = &field.ident;
					let field_name = field_ident.as_ref().unwrap().to_string();

					assignments.push(quote! {
						if let Some(value) = table.remove(#field_name) {
							if !matches!(value.get_ref(), toml::de::DeValue::Table(_)) {
								_ = toml::Table::deserialize(value.into_deserializer())?;
								return Err(serde::de::Error::custom(format!("expected top-level `{}` to be a TOML table", #field_name)));
							}