blaze_proc/
lib.rs

1#![allow(clippy::all)]
2
3macro_rules! flat_mod {
4    ($($i:ident),+) => {
5        $(
6            mod $i;
7            pub use $i::*;
8        )+
9    }
10}
11
12use cl::Link;
13use derive_syn_parse::Parse;
14use error::Error;
15use proc_macro2::{Ident, TokenStream};
16use quote::{format_ident, quote, ToTokens};
17use syn::{
18    parse_macro_input, parse_quote, punctuated::Punctuated, DeriveInput, Generics, ItemStatic,
19    ItemType, Meta, Visibility, WhereClause, WherePredicate,
20};
21
22use crate::cl::Blaze;
23
24mod cl;
25mod context;
26mod error;
27mod num;
28mod utils;
29
30#[proc_macro_derive(NumOps, attributes(uninit))]
31pub fn derive_num_ops(items: proc_macro::TokenStream) -> proc_macro::TokenStream {
32    let items = parse_macro_input!(items as DeriveInput);
33    num::derive_ops(items).into()
34}
35
36#[proc_macro_derive(NumOpsAssign, attributes(uninit))]
37pub fn derive_num_ops_assign(items: proc_macro::TokenStream) -> proc_macro::TokenStream {
38    let items = parse_macro_input!(items as DeriveInput);
39    num::derive_ops_assign(items).into()
40}
41
42#[proc_macro_attribute]
43pub fn global_context(
44    _attrs: proc_macro::TokenStream,
45    items: proc_macro::TokenStream,
46) -> proc_macro::TokenStream {
47    let items = parse_macro_input!(items as ItemStatic);
48    context::global_context(items).into()
49}
50
51#[proc_macro]
52pub fn error(items: proc_macro::TokenStream) -> proc_macro::TokenStream {
53    let input = parse_macro_input!(items as Error);
54    input.to_token_stream().into()
55}
56
57#[proc_macro_attribute]
58pub fn newtype(
59    attrs: proc_macro::TokenStream,
60    items: proc_macro::TokenStream,
61) -> proc_macro::TokenStream {
62    fn extra_where(where_generics: Option<&WhereClause>, extra: WherePredicate) -> WhereClause {
63        match where_generics {
64            Some(x) => {
65                let mut x = x.clone();
66                x.predicates.push(extra);
67                return x;
68            }
69
70            None => {
71                let mut predicates = Punctuated::new();
72                predicates.push(extra);
73
74                WhereClause {
75                    where_token: Default::default(),
76                    predicates,
77                }
78            }
79        }
80    }
81
82    let inner_vis = parse_macro_input!(attrs as Visibility);
83    let ItemType {
84        attrs,
85        vis,
86        ident,
87        generics,
88        ty,
89        semi_token,
90        ..
91    } = parse_macro_input!(items as ItemType);
92    let (impl_generics, ty_generics, where_generics) = generics.split_for_impl();
93
94    let consumer_generics = extra_where(
95        r#where_generics,
96        parse_quote! { #ty: blaze_rs::event::Consumer },
97    );
98    let debug_generics = extra_where(r#where_generics, parse_quote! { #ty: ::core::fmt::Debug });
99    let clone_generics = extra_where(r#where_generics, parse_quote! { #ty: ::core::clone::Clone });
100    let copy_generics = extra_where(r#where_generics, parse_quote! { #ty: ::core::marker::Copy });
101
102    quote! {
103        #(#attrs)*
104        #vis struct #ident #impl_generics (#inner_vis #ty) #semi_token
105
106        impl #impl_generics blaze_rs::event::Consumer for #ident #ty_generics #consumer_generics {
107            type Output = <#ty as blaze_rs::event::Consumer>::Output;
108
109            #[inline(always)]
110            unsafe fn consume (self) -> blaze_rs::prelude::Result<Self::Output> {
111                <#ty as blaze_rs::event::Consumer>::consume(self.0)
112            }
113        }
114
115        impl #impl_generics ::core::fmt::Debug for #ident #ty_generics #debug_generics {
116            #[inline(always)]
117            fn fmt (&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
118                ::core::fmt::Debug::fmt(&self.0, f)
119            }
120        }
121
122        impl #impl_generics ::core::clone::Clone for #ident #ty_generics #clone_generics {
123            #[inline(always)]
124            fn clone (&self) -> Self {
125                Self(::core::clone::Clone::clone(&self.0))
126            }
127        }
128
129        impl #impl_generics ::core::marker::Copy for #ident #ty_generics #copy_generics {}
130    }
131    .into()
132}
133
134#[proc_macro]
135pub fn join_various_blocking(items: proc_macro::TokenStream) -> proc_macro::TokenStream {
136    #[derive(Parse)]
137    struct Input(#[call(Punctuated::parse_terminated)] Punctuated<syn::Expr, syn::Token![,]>);
138
139    let item = parse_macro_input!(items as Input).0.into_iter();
140    let idx = (0..item.len()).map(syn::Index::from).collect::<Vec<_>>();
141
142    quote! {{
143        let v = (#(blaze_rs::event::Event::into_parts(#item)),*);
144        let (raw, consumer) = ([#(v.#idx.0),*], (#(v.#idx.1),*));
145        blaze_rs::event::RawEvent::join_all_by_ref(&raw).and_then(|_| unsafe {
146            Ok((
147                #(
148                    blaze_rs::event::Consumer::consume(consumer.#idx)?
149                ),*
150            ))
151        })
152    }}
153    .into()
154}
155
156#[proc_macro_attribute]
157pub fn blaze(
158    attrs: proc_macro::TokenStream,
159    items: proc_macro::TokenStream,
160) -> proc_macro::TokenStream {
161    let ident = parse_macro_input!(attrs as BlazeIdent);
162    let items = parse_macro_input!(items as Blaze);
163
164    let mut inner = None;
165    for attr in &items.attrs {
166        if attr.path.is_ident(&format_ident!("link")) {
167            let tokens = attr.tokens.clone().into();
168            let link = parse_macro_input!(tokens as Link);
169            inner = Some(link.meta);
170            break;
171        }
172    }
173
174    if let Some(inner) = inner {
175        return cl::blaze_c(ident.vis, ident.ident, ident.generics, items, inner).into();
176    }
177
178    panic!("No source code specified");
179}
180
181#[proc_macro_attribute]
182pub fn docfg(
183    attrs: proc_macro::TokenStream,
184    items: proc_macro::TokenStream,
185) -> proc_macro::TokenStream {
186    let attrs = parse_macro_input!(attrs as Meta);
187    let items = parse_macro_input!(items as TokenStream);
188
189    quote! {
190        #[cfg_attr(docsrs, doc(cfg(#attrs)))]
191        #[cfg(#attrs)]
192        #items
193    }
194    .into()
195}
196
197#[derive(Parse)]
198struct BlazeIdent {
199    vis: Visibility,
200    ident: Ident,
201    generics: Generics,
202}