serde_seeded_derive/
lib.rs

1//! This is a companion crate for [`serde-seeded`] defining the
2//! `SerializeSeeded` and `DeserializeSeeded` derive macros. It is not
3//! recommended to use this crate directly. Use the `serde-seeded` crate
4//! directly instead with the `derive` feature enabled.
5//!
6//! [`serde-seeded`]: <https://crates.io/crates/serde-seeded>
7use attributes::FieldAttributes;
8use proc_macro::TokenStream;
9use proc_macro2::Span;
10use proc_macro_error::{abort, proc_macro_error};
11use quote::format_ident;
12use syn::{parse_macro_input, spanned::Spanned};
13
14pub(crate) mod attributes;
15mod de;
16mod ser;
17pub(crate) mod utils;
18
19/// Derive macro implementing the `SerializeSeeded` trait automatically.
20///
21/// This macro is available through the `derive` feature.
22#[proc_macro_derive(SerializeSeeded, attributes(seeded))]
23#[proc_macro_error]
24pub fn derive_serialize(input: TokenStream) -> TokenStream {
25	let input = parse_macro_input!(input as syn::DeriveInput);
26	match ser::derive(input) {
27		Ok(tokens) => tokens.into(),
28		Err(e) => {
29			abort!(e.span(), e.to_string())
30		}
31	}
32}
33
34/// Derive macro implementing the `DeserializeSeeded` trait automatically.
35///
36/// This macro is available through the `derive` feature.
37#[proc_macro_derive(DeserializeSeeded, attributes(seeded))]
38#[proc_macro_error]
39pub fn derive_deserialize(input: TokenStream) -> TokenStream {
40	let input = parse_macro_input!(input as syn::DeriveInput);
41	match de::derive(input) {
42		Ok(tokens) => tokens.into(),
43		Err(e) => {
44			abort!(e.span(), e.to_string())
45		}
46	}
47}
48
49enum SerializedFields {
50	Unit,
51	Unnamed(Vec<SerializedUnnamedField>),
52	Named(Vec<SerializedNamedField>),
53}
54
55impl SerializedFields {
56	fn new(fields: &syn::Fields) -> Result<Self, attributes::Error> {
57		match fields {
58			syn::Fields::Unit => Ok(Self::Unit),
59			syn::Fields::Unnamed(fields) => fields
60				.unnamed
61				.iter()
62				.enumerate()
63				.map(|(i, f)| {
64					Ok(SerializedUnnamedField {
65						attrs: FieldAttributes::parse_attributes(&f.attrs)?,
66						index: i.into(),
67						id: format_ident!("arg_{i}"),
68						ty: f.ty.clone(),
69					})
70				})
71				.collect::<Result<_, _>>()
72				.map(Self::Unnamed),
73			syn::Fields::Named(fields) => fields
74				.named
75				.iter()
76				.map(|f| {
77					Ok(SerializedNamedField {
78						attrs: FieldAttributes::parse_attributes(&f.attrs)?,
79						id: f.ident.clone().unwrap(),
80						ty: f.ty.clone(),
81						span: f.span(),
82					})
83				})
84				.collect::<Result<_, _>>()
85				.map(Self::Named),
86		}
87	}
88}
89
90struct SerializedUnnamedField {
91	attrs: FieldAttributes,
92	index: syn::Index,
93	id: syn::Ident,
94	ty: syn::Type,
95}
96
97struct SerializedNamedField {
98	attrs: FieldAttributes,
99	id: syn::Ident,
100	ty: syn::Type,
101	span: Span,
102}
103
104impl SerializedNamedField {
105	pub fn name(&self) -> String {
106		self.attrs.name(&self.id)
107	}
108}