async_event_streams_derive/
lib.rs

1//!
2//! Crate allows to automatically derive [EventSink](async_event_streams::EventSink) trait for any
3//! structure implementing [EventSintExt](async_event_streams::EventSinkExt)
4//!
5//! Usage sample:
6//! ```
7//! use std::sync::Arc;
8//! use async_trait::async_trait;
9//! use std::borrow::Cow;
10//! use async_event_streams::{EventBox, EventSink, EventSinkExt};
11//! use async_event_streams_derive::EventSink;
12//!
13//! #[derive(EventSink)]
14//! #[event_sink(event=Event)]
15//! struct Sink;
16//!
17//! #[derive(Clone)]
18//! struct Event;
19//!
20//! #[async_trait]
21//! impl EventSinkExt<Event> for Sink {
22//!     type Error = ();
23//!     async fn on_event<'a>(&'a self, event: Cow<'a, Event>, source: Option<Arc<EventBox>>) -> Result<(), Self::Error> {
24//!         todo!()
25//!     }
26//!}
27//! ```
28mod param;
29
30use param::{take_params, Param};
31use quote::quote;
32use syn::{parse::ParseStream, parse_macro_input, DeriveInput, Ident};
33
34extern crate proc_macro;
35
36#[proc_macro_derive(EventSink, attributes(event_sink))]
37pub fn derive_event_sink(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
38    let input: DeriveInput = parse_macro_input!(input);
39    match derive_event_sink_impl(input) {
40        Ok(stream) => stream,
41        Err(e) => e.into_compile_error(),
42    }
43    .into()
44}
45
46fn derive_event_sink_impl(mut input: DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
47    let mut derives = Vec::new();
48    if let Some(params) = take_params::<StructParam>("event_sink", &mut input.attrs)? {
49        for param in params {
50            match param {
51                StructParam::Event(Ok(v)) => {
52                    derives.push(derive_event_sink_for_event(&input.ident, v)?)
53                }
54                StructParam::Event(Err(e)) => return Err(e),
55            }
56        }
57    }
58    let mut res = proc_macro2::TokenStream::new();
59    res.extend(derives.into_iter());
60    Ok(res)
61}
62
63fn derive_event_sink_for_event(
64    struct_id: &Ident,
65    event_id: Ident,
66) -> syn::Result<proc_macro2::TokenStream> {
67    Ok(quote! {
68        #[async_trait]
69        impl EventSink<#event_id> for #struct_id {
70            type Error = <#struct_id as EventSinkExt<#event_id>>::Error;
71            async fn on_event_ref(
72                &self,
73                event: &#event_id,
74                source: Option<Arc<EventBox>>,
75            ) -> Result<(), Self::Error> {
76                <#struct_id as EventSinkExt<#event_id>>::on_event(&self, Cow::Borrowed(event), source).await
77            }
78            async fn on_event_owned(
79                &self,
80                event: #event_id,
81                source: Option<Arc<EventBox>>,
82            ) -> Result<(), Self::Error> {
83                <#struct_id as EventSinkExt<#event_id>>::on_event(&self, Cow::Owned(event), source).await
84            }
85        }
86    })
87}
88
89enum StructParam {
90    Event(Result<Ident, syn::Error>),
91}
92
93impl Param for StructParam {
94    fn default(name: Ident) -> syn::Result<Self> {
95        if name == "event" {
96            return Ok(StructParam::Event(Err(syn::Error::new(
97                name.span(),
98                "Event name expected",
99            ))));
100        } else {
101            Err(syn::Error::new(
102                name.span(),
103                "Unexpected parameter. Allowed value is 'event'",
104            ))
105        }
106    }
107    fn parse(&mut self, input: ParseStream) -> syn::Result<()> {
108        match self {
109            StructParam::Event(ref mut v) => *v = Ok(input.parse()?),
110        }
111        Ok(())
112    }
113}