gmt_dos_clients_scope_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{
4    bracketed, parenthesized, parse::Parse, parse_macro_input, Expr, Ident, LitInt, LitStr, Token,
5};
6
7/**
8Signal plotting scope
9
10## Example
11
12```ignore
13use gmt_dos_clients_scope::client;
14
15let server_ip = "127.0.0.1";
16let server_port = 5001;
17let client_address = "127.0.0.1:0";
18
19client::scope!(server_ip, client_address, [(Signal, server_port)]);
20```
21
22*/
23#[proc_macro]
24pub fn scope(input: TokenStream) -> TokenStream {
25    let input = parse_macro_input!(input as Scope);
26    let scope = input.scope();
27    let variables = input.variables();
28    let signals = input.signals();
29    let expanded = quote! {
30        #(#variables)*
31        #scope
32        #(#signals)*
33        .show();
34    };
35    TokenStream::from(expanded)
36}
37
38/**
39Image display scope
40
41## Example
42
43```ignore
44use gmt_dos_clients_scope::client;
45
46let server_ip = "127.0.0.1";
47let server_port = 5001;
48let client_address = "127.0.0.1:0";
49
50client::shot!(server_ip, client_address, [(Signal, server_port)]);
51```
52*/
53#[proc_macro]
54pub fn shot(input: TokenStream) -> TokenStream {
55    let input = parse_macro_input!(input as Scope);
56    let scope = input.shot();
57    let variables = input.images();
58    let signals = input.signals();
59    let expanded = quote! {
60        #(#variables)*
61        #scope
62        #(#signals)*
63        .show();
64    };
65    TokenStream::from(expanded)
66}
67
68/**
69GMT scope
70
71## Example
72
73```ignore
74use gmt_dos_clients_scope::client;
75
76let server_ip = "127.0.0.1";
77let server_port = 5001;
78let client_address = "127.0.0.1:0";
79
80client::gmt_scope!(server_ip, client_address, [(GmtWavefront, server_port)]);
81```
82*/
83#[proc_macro]
84pub fn gmt_shot(input: TokenStream) -> TokenStream {
85    let input = parse_macro_input!(input as Scope);
86    let scope = input.gmt_shot();
87    let variables = input.gmt_images();
88    let signals = input.signals();
89    let expanded = quote! {
90        #(#variables)*
91        #scope
92        #(#signals)*
93        .show();
94    };
95    TokenStream::from(expanded)
96}
97
98enum Port {
99    LitInt(LitInt),
100    Expr(Expr),
101}
102impl From<LitInt> for Port {
103    fn from(value: LitInt) -> Self {
104        Self::LitInt(value)
105    }
106}
107impl From<Expr> for Port {
108    fn from(value: Expr) -> Self {
109        Self::Expr(value)
110    }
111}
112impl Port {
113    pub fn port(&self) -> proc_macro2::TokenStream {
114        match self {
115            Port::LitInt(value) => quote!(#value),
116            Port::Expr(value) => quote!(#value),
117        }
118    }
119}
120
121struct Signal {
122    ident: Ident,
123    port: Port,
124}
125impl Signal {
126    fn variable(&self) -> proc_macro2::TokenStream {
127        let Signal { ident, .. } = self;
128        quote!(
129            #[derive(::gmt_dos_clients::interface::UID)]
130            #[uid(data = f64)]
131            pub enum #ident {}
132        )
133    }
134    fn image(&self) -> proc_macro2::TokenStream {
135        let Signal { ident, .. } = self;
136        quote!(
137            #[derive(::gmt_dos_clients::interface::UID)]
138            pub enum #ident {}
139        )
140    }
141    fn gmt_image(&self) -> proc_macro2::TokenStream {
142        let Signal { ident, .. } = self;
143        quote!(
144            #[derive(::gmt_dos_clients::interface::UID)]
145            #[uid(data = (Vec<f64>,Vec<bool>))]
146            pub enum #ident {}
147        )
148    }
149    fn signal(&self) -> proc_macro2::TokenStream {
150        let Signal { ident, port } = self;
151        let port = port.port();
152        quote! {
153            .signal::<#ident>(#port)?
154        }
155    }
156}
157
158impl Parse for Signal {
159    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
160        let ident: Ident = input.parse()?;
161        input.parse::<Token![,]>()?;
162        let port: Port = if let Ok(port) = input.parse::<LitInt>() {
163            Ok(port.into())
164        } else {
165            input.parse::<Expr>().map(|port| Port::from(port))
166        }?;
167        Ok(Self { ident, port })
168    }
169}
170
171struct ParenthesizedSignal(Signal);
172
173impl Parse for ParenthesizedSignal {
174    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
175        let content;
176        let _ = parenthesized!(content in input);
177        let signal: Signal = content.parse()?;
178        Ok(Self(signal))
179    }
180}
181
182// #[derive(Debug)]
183struct Scope {
184    server_address: LitStr,
185    client_address: LitStr,
186    signals: Vec<Signal>,
187}
188
189impl Scope {
190    pub fn scope(&self) -> proc_macro2::TokenStream {
191        let Self {
192            server_address,
193            client_address,
194            ..
195        } = self;
196        quote! {
197            ::gmt_dos_clients_scope::client::Scope::new(#server_address, #client_address)
198        }
199    }
200    pub fn shot(&self) -> proc_macro2::TokenStream {
201        let Self {
202            server_address,
203            client_address,
204            ..
205        } = self;
206        quote! {
207            ::gmt_dos_clients_scope::client::Shot::new(#server_address, #client_address)
208        }
209    }
210    pub fn gmt_shot(&self) -> proc_macro2::TokenStream {
211        let Self {
212            server_address,
213            client_address,
214            ..
215        } = self;
216        quote! {
217            ::gmt_dos_clients_scope::client::GmtShot::new(#server_address, #client_address)
218        }
219    }
220    pub fn signals(&self) -> Vec<proc_macro2::TokenStream> {
221        self.signals.iter().map(|signal| signal.signal()).collect()
222    }
223    pub fn variables(&self) -> Vec<proc_macro2::TokenStream> {
224        self.signals
225            .iter()
226            .map(|signal| signal.variable())
227            .collect()
228    }
229    pub fn images(&self) -> Vec<proc_macro2::TokenStream> {
230        self.signals.iter().map(|signal| signal.image()).collect()
231    }
232    pub fn gmt_images(&self) -> Vec<proc_macro2::TokenStream> {
233        self.signals
234            .iter()
235            .map(|signal| signal.gmt_image())
236            .collect()
237    }
238}
239
240impl Parse for Scope {
241    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
242        let server_address: LitStr = input.parse()?;
243        input.parse::<Token![,]>()?;
244        let client_address: LitStr = input.parse()?;
245        input.parse::<Token![,]>()?;
246
247        let content;
248        let _ = bracketed!(content in input);
249        let signals: Vec<_> = content
250            .parse_terminated(ParenthesizedSignal::parse, Token![,])?
251            .into_iter()
252            .map(|x| x.0)
253            .collect();
254
255        Ok(Self {
256            server_address,
257            client_address,
258            signals,
259        })
260    }
261}