track_macro/
lib.rs

1extern crate proc_macro;
2
3use darling::FromMeta;
4use proc_macro::TokenStream;
5use quote::quote;
6use syn::{parse_macro_input, AttributeArgs, DeriveInput, Ident};
7
8#[derive(Debug, FromMeta)]
9struct MacroArgs {
10    #[darling(default)]
11    serialization: Option<Ident>,
12}
13
14/// A macro attribute that indicates a type that needs to be tracked and implements
15/// [Trackable](https://docs.rs/track/trait.Trackable.html) and [TrackableMarker](https://docs.rs/track/trait.TrackableMarker.html).
16///
17/// # Examples
18///
19/// Add `track` attribute to mark your struct as trackable.
20///
21/// ```rust
22/// // imports all necessarily types for the `track` attribute.
23/// use track::preclude::*;
24///
25/// #[track]
26/// #[derive(Debug)]
27/// pub struct Position {
28///     pub x: u32,
29///     pub y: u32,
30/// }
31/// ```
32///
33/// You can specify a serialization method for the track macro.
34/// Give the name of the type that implements [SerializationStrategy](https://docs.rs/track/serialization/trait.SerializationStrategy.html), and make sure it is in scope for the macro.
35/// Such as:
36///
37/// ```rust
38/// use track::serialization::bincode::Bincode;
39///
40/// #[track(serialization = "Bincode")]
41/// struct Postition ...
42/// ```
43///
44/// For a more in-depth example checkout the [examples](https://github.com/entity-sync-rs/track/tree/master/examples) on github.
45#[proc_macro_attribute]
46pub fn track(_attr: TokenStream, unparsed_input: TokenStream) -> TokenStream {
47    let attr_args = parse_macro_input!(_attr as AttributeArgs);
48    let input: DeriveInput = parse_macro_input!(unparsed_input as syn::DeriveInput);
49
50    let _args = match MacroArgs::from_list(&attr_args) {
51        Ok(v) => v,
52        Err(e) => {
53            return proc_macro::TokenStream::from(e.write_errors());
54        }
55    };
56
57    let serialization = if let Some(ser) = _args.serialization {
58        ser
59    } else {
60        Ident::from_string("Bincode").unwrap()
61    };
62
63    let name = input.ident.clone();
64
65    let implementation = quote! {
66        #[derive(Clone, SerdeDiff, Serialize, Deserialize)]
67        #input
68
69        impl Trackable<#name, #serialization> for #name {
70            fn track<'notifier, I: Identifier>(&mut self, sender: &'notifier Sender<ModificationEvent<I>>, identifier: I) -> Tracker<'_, 'notifier, #name,  #serialization, I> {
71                Tracker::new(self, sender, #serialization, identifier)
72            }
73        }
74
75        impl TrackableMarker for #name { }
76    };
77
78    proc_macro::TokenStream::from(implementation)
79}