1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use proc_macro2::TokenStream as TokenStream2;
5use quote::quote;
6
7mod diff;
8mod firewheel_manifest;
9mod patch;
10
11#[proc_macro_derive(Diff, attributes(diff))]
12pub fn derive_diff(input: TokenStream) -> TokenStream {
13 diff::derive_diff(input)
14 .unwrap_or_else(syn::Error::into_compile_error)
15 .into()
16}
17
18#[proc_macro_derive(Patch, attributes(diff))]
19pub fn derive_patch(input: TokenStream) -> TokenStream {
20 patch::derive_patch(input)
21 .unwrap_or_else(syn::Error::into_compile_error)
22 .into()
23}
24
25fn get_paths() -> (syn::Path, TokenStream2) {
26 let firewheel_path =
27 firewheel_manifest::FirewheelManifest::default().get_path("firewheel_core");
28 let diff_path = quote! { #firewheel_path::diff };
29
30 (firewheel_path, diff_path)
31}
32
33fn should_skip(attrs: &[syn::Attribute]) -> bool {
34 let mut skip = false;
35 for attr in attrs {
36 if attr.path().is_ident("diff") {
37 attr.parse_nested_meta(|meta| {
38 if meta.path.is_ident("skip") {
39 skip = true;
40 }
41
42 Ok(())
43 })
44 .expect("infallible operation");
45 }
46 }
47
48 skip
49}
50
51fn struct_fields(data: &syn::Fields) -> impl Iterator<Item = (syn::Member, &syn::Type)> {
52 data.iter()
56 .enumerate()
57 .filter(|(_, f)| !should_skip(&f.attrs))
58 .map(|(i, f)| (as_member(f.ident.as_ref(), i), &f.ty))
59}
60
61fn as_member(ident: Option<&syn::Ident>, index: usize) -> syn::Member {
62 ident.map_or_else(
63 || syn::Member::from(index),
64 |ident| syn::Member::Named(ident.clone()),
65 )
66}
67
68#[derive(Default)]
69struct TypeSet<'a>(Vec<&'a syn::Type>);
70
71impl<'a> TypeSet<'a> {
72 pub fn insert(&mut self, ty: &'a syn::Type) -> bool {
73 self.0.push(ty);
95 true
96 }
97}
98
99impl<'a> IntoIterator for TypeSet<'a> {
100 type Item = &'a syn::Type;
101 type IntoIter = <Vec<&'a syn::Type> as IntoIterator>::IntoIter;
102
103 fn into_iter(self) -> Self::IntoIter {
104 self.0.into_iter()
105 }
106}
107
108impl<'a> core::ops::Deref for TypeSet<'a> {
109 type Target = [&'a syn::Type];
110
111 fn deref(&self) -> &Self::Target {
112 &self.0
113 }
114}