interlink_derive/
lib.rs

1use darling::{FromDeriveInput, FromMeta};
2use proc_macro::TokenStream;
3use quote::quote;
4use syn::{parse_macro_input, DeriveInput, Ident, Type};
5
6/// Options for a message derive
7#[derive(FromDeriveInput, Default)]
8#[darling(default, attributes(msg), forward_attrs(allow, doc, cfg))]
9struct MessageOpts {
10    /// Response type for the message
11    rtype: Option<Type>,
12}
13
14/// Macro for deriving the Message trait to allow something to be
15/// sent as a message
16///
17///
18/// ```
19/// use interlink::prelude::*;
20///
21/// /// Default message response type is ()
22/// #[derive(Message)]
23/// struct MyMessage;
24///
25/// /// Message with a string response type
26/// #[derive(Message)]
27/// #[msg(rtype = "String")]
28/// struct MySecondMessage;
29///
30/// ```
31#[proc_macro_derive(Message, attributes(msg))]
32pub fn derive_message_impl(input: TokenStream) -> TokenStream {
33    let input: DeriveInput = parse_macro_input!(input);
34    let opts: MessageOpts = MessageOpts::from_derive_input(&input).expect("Invalid options");
35
36    let ident: Ident = input.ident;
37
38    let rtype: Type = match opts.rtype {
39        // Custom response type
40        Some(value) => value,
41        // Default unit response type
42        None => Type::from_string("()").unwrap(),
43    };
44
45    quote! {
46        impl interlink::msg::Message for #ident {
47            type Response = #rtype;
48        }
49    }
50    .into()
51}
52
53/// Macro for deriving a basic Service implementation without
54/// having any of the started and stopping hooks
55#[proc_macro_derive(Service)]
56pub fn derive_service_impl(input: TokenStream) -> TokenStream {
57    let input: DeriveInput = parse_macro_input!(input);
58    let ident = input.ident;
59    quote! {
60        impl interlink::service::Service for #ident { }
61    }
62    .into()
63}