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
25#[proc_macro_derive(RealtimeClone)]
29pub fn derive_realtime_clone(input: TokenStream) -> TokenStream {
30 derive_realtime_clone_inner(input)
31 .unwrap_or_else(syn::Error::into_compile_error)
32 .into()
33}
34
35fn derive_realtime_clone_inner(input: TokenStream) -> syn::Result<TokenStream2> {
36 let input: syn::DeriveInput = syn::parse(input)?;
37 let identifier = &input.ident;
38 let (_, diff_path) = get_paths();
39
40 let (impl_generics, ty_generics, where_generics) = input.generics.split_for_impl();
41
42 Ok(quote! {
43 #[automatically_derived]
44 impl #impl_generics #diff_path::RealtimeClone for #identifier #ty_generics #where_generics {}
45 })
46}
47
48fn get_paths() -> (syn::Path, TokenStream2) {
49 let firewheel_path =
50 firewheel_manifest::FirewheelManifest::default().get_path("firewheel_core");
51 let diff_path = quote! { #firewheel_path::diff };
52
53 (firewheel_path, diff_path)
54}
55
56fn should_skip(attrs: &[syn::Attribute]) -> bool {
57 let mut skip = false;
58 for attr in attrs {
59 if attr.path().is_ident("diff") {
60 attr.parse_nested_meta(|meta| {
61 if meta.path.is_ident("skip") {
62 skip = true;
63 }
64
65 Ok(())
66 })
67 .expect("infallible operation");
68 }
69 }
70
71 skip
72}
73
74fn struct_fields(data: &syn::Fields) -> impl Iterator<Item = (syn::Member, &syn::Type)> {
75 data.iter()
79 .enumerate()
80 .filter(|(_, f)| !should_skip(&f.attrs))
81 .map(|(i, f)| (as_member(f.ident.as_ref(), i), &f.ty))
82}
83
84fn as_member(ident: Option<&syn::Ident>, index: usize) -> syn::Member {
85 ident.map_or_else(
86 || syn::Member::from(index),
87 |ident| syn::Member::Named(ident.clone()),
88 )
89}
90
91#[derive(Default)]
92struct TypeSet<'a>(Vec<&'a syn::Type>);
93
94impl<'a> TypeSet<'a> {
95 pub fn insert(&mut self, ty: &'a syn::Type) -> bool {
96 self.0.push(ty);
118 true
119 }
120}
121
122impl<'a> IntoIterator for TypeSet<'a> {
123 type Item = &'a syn::Type;
124 type IntoIter = <Vec<&'a syn::Type> as IntoIterator>::IntoIter;
125
126 fn into_iter(self) -> Self::IntoIter {
127 self.0.into_iter()
128 }
129}
130
131impl<'a> core::ops::Deref for TypeSet<'a> {
132 type Target = [&'a syn::Type];
133
134 fn deref(&self) -> &Self::Target {
135 &self.0
136 }
137}