dos_uid_derive/lib.rs
1/*!
2# UID
3
4A derive macro that implements the [UniqueIdentifier] trait.
5
6## Examples
7
8Setting the data type and port # to the default values: `Vec<f64>` and `50_000u32`, respectively:
9```
10use interface::UID;
11
12#[derive(UID)]
13enum Tag {}
14```
15
16The data type and port # are set with:
17```
18use interface::UID;
19
20struct Q<T>(std::marker::PhantomData<T>);
21
22enum ID {}
23
24#[derive(UID)]
25#[uid(data = Q<ID>, port = 9999)]
26enum TU {}
27```
28
29An alias is a type that implements the [Read], [Write] or [Size] trait of another type that implements the same traits for the same client:
30```
31use interface::{UID, Data, Read, Size, Update, Write};
32# struct Q<T>(std::marker::PhantomData<T>);
33# enum ID {}
34# #[derive(UID)]
35# #[uid(data = Q<ID>, port = 9999)]
36# enum TU {}
37
38struct Client {}
39impl Update for Client {}
40impl Write<TU> for Client {
41 fn write(&mut self) -> Option<Data<TU>> {
42 None
43 }
44}
45impl Read<TU> for Client {
46 fn read(&mut self, _data: Data<TU>) {}
47}
48impl Size<TU> for Client {
49 fn len(&self) -> usize {
50 1234
51 }
52}
53
54#[derive(UID)]
55#[alias(name = TU, client = Client, traits = Write, Read, Size)]
56enum TUT {}
57```
58
59[UniqueIdentifier]: https://docs.rs/gmt_dos-clients/latest/gmt_dos_clients/interface/trait.UniqueIdentifier.html
60[Read]: https://docs.rs/gmt_dos-clients/latest/gmt_dos_clients/interface/trait.Read.html
61[Write]: https://docs.rs/gmt_dos-clients/latest/gmt_dos_clients/interface/trait.Write.html
62[Size]: https://docs.rs/gmt_dos-clients/latest/gmt_dos_clients/interface/trait.Size.html
63*/
64
65use proc_macro::TokenStream;
66use quote::quote;
67use syn::{parse_macro_input, DeriveInput};
68
69#[proc_macro_derive(UID, attributes(uid, alias))]
70pub fn derive(input: TokenStream) -> TokenStream {
71 let input = parse_macro_input!(input as DeriveInput);
72 Parser::new(&input)
73 .map_or_else(syn::Error::into_compile_error, |parser| {
74 if let Some(alias_attrs) = parser.alias_attrs {
75 let aliases: Vec<_> = alias_attrs
76 .iter()
77 .map(|alias| alias.expand(&input))
78 .collect();
79 quote!(#(#aliases)*)
80 } else {
81 parser.uid_attrs.expand(&input)
82 }
83 })
84 .into()
85}
86
87mod alias;
88mod uid;
89
90/// Derive attributes parser
91///
92/// #[uid(...)]
93/// #[alias(...)]
94#[derive(Debug, Clone, Default)]
95struct Parser {
96 pub uid_attrs: uid::Attributes,
97 pub alias_attrs: Option<Vec<alias::Attributes>>,
98}
99
100impl Parser {
101 fn new(input: &DeriveInput) -> syn::Result<Parser> {
102 let mut parser: Parser = Default::default();
103 for attr in &input.attrs {
104 if attr.path().is_ident("uid") {
105 parser.uid_attrs = attr.parse_args()?;
106 }
107 if attr.path().is_ident("alias") {
108 parser
109 .alias_attrs
110 .get_or_insert(vec![])
111 .push(attr.parse_args()?);
112 }
113 }
114 parser
115 .alias_attrs
116 .iter_mut()
117 .flatten()
118 .skip(1)
119 .for_each(|alias| {
120 alias.skip_uid = true;
121 });
122 Ok(parser)
123 }
124}
125
126type Expanded = proc_macro2::TokenStream;
127
128trait Expand {
129 fn expand(&self, input: &DeriveInput) -> Expanded;
130}