yazi_codegen/
lib.rs

1use proc_macro::TokenStream;
2use quote::{format_ident, quote};
3use syn::{Attribute, Data, DeriveInput, Fields, parse_macro_input};
4
5#[proc_macro_derive(DeserializeOver1)]
6pub fn deserialize_over1(input: TokenStream) -> TokenStream {
7	// Parse the input tokens into a syntax tree
8	let input = parse_macro_input!(input as DeriveInput);
9
10	// Get the name of the struct
11	let name = &input.ident;
12	let shadow_name = format_ident!("__{name}Shadow");
13
14	// Process the struct fields
15	let (shadow_fields, field_calls) = match &input.data {
16		Data::Struct(struct_) => match &struct_.fields {
17			Fields::Named(fields) => {
18				let mut shadow_fields = Vec::with_capacity(fields.named.len());
19				let mut field_calls = Vec::with_capacity(fields.named.len());
20
21				for field in &fields.named {
22					let name = &field.ident;
23					let attrs: Vec<&Attribute> =
24						field.attrs.iter().filter(|&a| a.path().is_ident("serde")).collect();
25
26					shadow_fields.push(quote! {
27							#(#attrs)*
28							pub(crate) #name: Option<toml::Value>
29					});
30					field_calls.push(quote! {
31						if let Some(value) = shadow.#name {
32							self.#name = self.#name.deserialize_over(value).map_err(serde::de::Error::custom)?;
33						}
34					});
35				}
36
37				(shadow_fields, field_calls)
38			}
39			_ => panic!("DeserializeOver1 only supports structs with named fields"),
40		},
41		_ => panic!("DeserializeOver1 only supports structs"),
42	};
43
44	quote! {
45		#[derive(serde::Deserialize)]
46		pub(crate) struct #shadow_name {
47			#(#shadow_fields),*
48		}
49
50		impl #name {
51			#[inline]
52			pub(crate) fn deserialize_over<'de, D>(self, deserializer: D) -> Result<Self, D::Error>
53			where
54				D: serde::Deserializer<'de>,
55			{
56				self.deserialize_over_with::<D>(Self::deserialize_shadow(deserializer)?)
57			}
58
59			#[inline]
60			pub(crate) fn deserialize_shadow<'de, D>(deserializer: D) -> Result<#shadow_name, D::Error>
61			where
62				D: serde::Deserializer<'de>,
63			{
64				#shadow_name::deserialize(deserializer)
65			}
66
67			#[inline]
68			pub(crate) fn deserialize_over_with<'de, D>(mut self, shadow: #shadow_name) -> Result<Self, D::Error>
69			where
70				D: serde::Deserializer<'de>,
71			{
72				#(#field_calls)*
73				Ok(self)
74			}
75		}
76	}
77	.into()
78}
79
80#[proc_macro_derive(DeserializeOver2)]
81pub fn deserialize_over2(input: TokenStream) -> TokenStream {
82	// Parse the input tokens into a syntax tree
83	let input = parse_macro_input!(input as DeriveInput);
84
85	// Get the name of the struct
86	let name = &input.ident;
87	let shadow_name = format_ident!("__{name}Shadow");
88
89	// Process the struct fields
90	let (shadow_fields, field_assignments) = match &input.data {
91		Data::Struct(struct_) => match &struct_.fields {
92			Fields::Named(fields) => {
93				let mut shadow_fields = Vec::with_capacity(fields.named.len());
94				let mut field_assignments = Vec::with_capacity(fields.named.len());
95
96				for field in &fields.named {
97					let (ty, name) = (&field.ty, &field.ident);
98					shadow_fields.push(quote! {
99						pub(crate) #name: Option<#ty>
100					});
101					field_assignments.push(quote! {
102						if let Some(value) = shadow.#name {
103							self.#name = value;
104						}
105					});
106				}
107
108				(shadow_fields, field_assignments)
109			}
110			_ => panic!("DeserializeOver2 only supports structs with named fields"),
111		},
112		_ => panic!("DeserializeOver2 only supports structs"),
113	};
114
115	quote! {
116		#[derive(serde::Deserialize)]
117		pub(crate) struct #shadow_name {
118			#(#shadow_fields),*
119		}
120
121		impl #name {
122			#[inline]
123			pub(crate) fn deserialize_over<'de, D>(mut self, deserializer: D) -> Result<Self, D::Error>
124			where
125				D: serde::Deserializer<'de>
126			{
127				Ok(self.deserialize_over_with(Self::deserialize_shadow(deserializer)?))
128			}
129
130			#[inline]
131			pub(crate) fn deserialize_shadow<'de, D>(deserializer: D) -> Result<#shadow_name, D::Error>
132			where
133				D: serde::Deserializer<'de>
134			{
135				#shadow_name::deserialize(deserializer)
136			}
137
138			#[inline]
139			pub(crate) fn deserialize_over_with(mut self, shadow: #shadow_name) -> Self {
140				#(#field_assignments)*
141				self
142			}
143		}
144	}
145	.into()
146}