arcly_stream_macros/
lib.rs1use proc_macro::TokenStream;
8use quote::quote;
9use syn::{parse_macro_input, Data, DeriveInput, Fields, Index, LitStr};
10
11#[proc_macro_derive(MediaSink, attributes(sink))]
26pub fn derive_media_sink(input: TokenStream) -> TokenStream {
27 let input = parse_macro_input!(input as DeriveInput);
28 let name = &input.ident;
29 let (impl_g, ty_g, where_c) = input.generics.split_for_impl();
30
31 let fields = match &input.data {
32 Data::Struct(s) => &s.fields,
33 _ => {
34 return syn::Error::new_spanned(name, "MediaSink can only be derived for structs")
35 .to_compile_error()
36 .into()
37 }
38 };
39
40 let accessor = match pick_delegate(fields) {
41 Ok(tokens) => tokens,
42 Err(e) => return e.to_compile_error().into(),
43 };
44
45 quote! {
46 #[::arcly_stream::__macro_support::async_trait]
47 impl #impl_g ::arcly_stream::traits::MediaSink for #name #ty_g #where_c {
48 async fn send_frame(
49 &mut self,
50 frame: ::arcly_stream::MediaFrame,
51 ) -> ::arcly_stream::Result<()> {
52 ::arcly_stream::traits::MediaSink::send_frame(&mut self.#accessor, frame).await
53 }
54 async fn flush(&mut self) -> ::arcly_stream::Result<()> {
55 ::arcly_stream::traits::MediaSink::flush(&mut self.#accessor).await
56 }
57 }
58 }
59 .into()
60}
61
62fn pick_delegate(fields: &Fields) -> syn::Result<proc_macro2::TokenStream> {
64 let marked = |attrs: &[syn::Attribute]| attrs.iter().any(|a| a.path().is_ident("sink"));
65 match fields {
66 Fields::Named(named) => {
67 let chosen = named
68 .named
69 .iter()
70 .find(|f| marked(&f.attrs))
71 .or_else(|| named.named.first());
72 match chosen {
73 Some(f) => {
74 let ident = f.ident.as_ref().expect("named field has ident");
75 Ok(quote!(#ident))
76 }
77 None => Err(syn::Error::new_spanned(
78 &named.named,
79 "MediaSink derive needs at least one field to delegate to",
80 )),
81 }
82 }
83 Fields::Unnamed(unnamed) => {
84 let idx = unnamed
85 .unnamed
86 .iter()
87 .position(|f| marked(&f.attrs))
88 .unwrap_or(0);
89 if unnamed.unnamed.is_empty() {
90 return Err(syn::Error::new_spanned(
91 &unnamed.unnamed,
92 "MediaSink derive needs at least one field to delegate to",
93 ));
94 }
95 let index = Index::from(idx);
96 Ok(quote!(#index))
97 }
98 Fields::Unit => Err(syn::Error::new_spanned(
99 fields,
100 "MediaSink cannot be derived for a unit struct (nothing to delegate to)",
101 )),
102 }
103}
104
105#[proc_macro_attribute]
119pub fn protocol(attr: TokenStream, item: TokenStream) -> TokenStream {
120 let lit = parse_macro_input!(attr as LitStr);
121 let input = parse_macro_input!(item as DeriveInput);
122 let name = &input.ident;
123 let (impl_g, ty_g, where_c) = input.generics.split_for_impl();
124 let value = lit.value();
125
126 quote! {
127 #input
128
129 impl #impl_g #name #ty_g #where_c {
130 pub const PROTOCOL_NAME: &'static str = #value;
132 }
133 }
134 .into()
135}