orchestra_proc_macro/parse/
parse_orchestra_attr.rs1use super::kw;
17use proc_macro2::Span;
18use quote::{quote, ToTokens};
19use std::collections::{hash_map::RandomState, HashMap};
20use syn::{
21 parse::{Parse, ParseBuffer},
22 punctuated::Punctuated,
23 spanned::Spanned,
24 Error, Ident, LitBool, LitInt, Path, Result, Token,
25};
26
27#[derive(Clone, Debug)]
28enum OrchestraAttrItem {
29 ExternEventType { tag: kw::event, eq_token: Token![=], value: Path },
30 ExternOrchestraSignalType { tag: kw::signal, eq_token: Token![=], value: Path },
31 ExternErrorType { tag: kw::error, eq_token: Token![=], value: Path },
32 OutgoingType { tag: kw::outgoing, eq_token: Token![=], value: Path },
33 MessageWrapperName { tag: kw::gen, eq_token: Token![=], value: Ident },
34 BoxedMessages { tag: kw::boxed_messages, eq_token: Token![=], value: bool },
35 SignalChannelCapacity { tag: kw::signal_capacity, eq_token: Token![=], value: usize },
36 MessageChannelCapacity { tag: kw::message_capacity, eq_token: Token![=], value: usize },
37}
38
39impl ToTokens for OrchestraAttrItem {
40 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
41 let ts = match self {
42 Self::ExternEventType { tag, eq_token, value } => {
43 quote! { #tag #eq_token, #value }
44 },
45 Self::ExternOrchestraSignalType { tag, eq_token, value } => {
46 quote! { #tag #eq_token, #value }
47 },
48 Self::ExternErrorType { tag, eq_token, value } => {
49 quote! { #tag #eq_token, #value }
50 },
51 Self::OutgoingType { tag, eq_token, value } => {
52 quote! { #tag #eq_token, #value }
53 },
54 Self::MessageWrapperName { tag, eq_token, value } => {
55 quote! { #tag #eq_token, #value }
56 },
57 Self::SignalChannelCapacity { tag, eq_token, value } => {
58 quote! { #tag #eq_token, #value }
59 },
60 Self::MessageChannelCapacity { tag, eq_token, value } => {
61 quote! { #tag #eq_token, #value }
62 },
63 Self::BoxedMessages { tag, eq_token, value } => {
64 quote! { #tag #eq_token, #value }
65 },
66 };
67 tokens.extend(ts.into_iter());
68 }
69}
70
71impl Parse for OrchestraAttrItem {
72 fn parse(input: &ParseBuffer) -> Result<Self> {
73 let lookahead = input.lookahead1();
74 if lookahead.peek(kw::event) {
75 Ok(OrchestraAttrItem::ExternEventType {
76 tag: input.parse::<kw::event>()?,
77 eq_token: input.parse()?,
78 value: input.parse()?,
79 })
80 } else if lookahead.peek(kw::signal) {
81 Ok(OrchestraAttrItem::ExternOrchestraSignalType {
82 tag: input.parse::<kw::signal>()?,
83 eq_token: input.parse()?,
84 value: input.parse()?,
85 })
86 } else if lookahead.peek(kw::error) {
87 Ok(OrchestraAttrItem::ExternErrorType {
88 tag: input.parse::<kw::error>()?,
89 eq_token: input.parse()?,
90 value: input.parse()?,
91 })
92 } else if lookahead.peek(kw::outgoing) {
93 Ok(OrchestraAttrItem::OutgoingType {
94 tag: input.parse::<kw::outgoing>()?,
95 eq_token: input.parse()?,
96 value: input.parse()?,
97 })
98 } else if lookahead.peek(kw::gen) {
99 Ok(OrchestraAttrItem::MessageWrapperName {
100 tag: input.parse::<kw::gen>()?,
101 eq_token: input.parse()?,
102 value: input.parse()?,
103 })
104 } else if lookahead.peek(kw::signal_capacity) {
105 Ok(OrchestraAttrItem::SignalChannelCapacity {
106 tag: input.parse::<kw::signal_capacity>()?,
107 eq_token: input.parse()?,
108 value: input.parse::<LitInt>()?.base10_parse::<usize>()?,
109 })
110 } else if lookahead.peek(kw::message_capacity) {
111 Ok(OrchestraAttrItem::MessageChannelCapacity {
112 tag: input.parse::<kw::message_capacity>()?,
113 eq_token: input.parse()?,
114 value: input.parse::<LitInt>()?.base10_parse::<usize>()?,
115 })
116 } else if lookahead.peek(kw::boxed_messages) {
117 Ok(OrchestraAttrItem::BoxedMessages {
118 tag: input.parse::<kw::boxed_messages>()?,
119 eq_token: input.parse()?,
120 value: input.parse::<LitBool>()?.value(),
121 })
122 } else {
123 Err(lookahead.error())
124 }
125 }
126}
127
128#[derive(Clone, Debug)]
130pub(crate) struct OrchestraAttrArgs {
131 pub(crate) message_wrapper: Ident,
132 pub(crate) extern_event_ty: Path,
133 pub(crate) extern_signal_ty: Path,
134 pub(crate) extern_error_ty: Path,
135 pub(crate) outgoing_ty: Option<Path>,
136 pub(crate) signal_channel_capacity: usize,
137 pub(crate) message_channel_capacity: usize,
138 pub(crate) boxed_messages: bool,
139}
140
141macro_rules! extract_variant {
142 ($unique:expr, $variant:ident ; default = $fallback:expr) => {
143 extract_variant!($unique, $variant).unwrap_or_else(|| $fallback)
144 };
145 ($unique:expr, $variant:ident ; err = $err:expr) => {
146 extract_variant!($unique, $variant).ok_or_else(|| Error::new(Span::call_site(), $err))
147 };
148 ($unique:expr, $variant:ident) => {
149 $unique.values().find_map(|item| {
150 if let OrchestraAttrItem::$variant { value, .. } = item {
151 Some(value.clone())
152 } else {
153 None
154 }
155 })
156 };
157}
158
159impl Parse for OrchestraAttrArgs {
160 fn parse(input: &ParseBuffer) -> Result<Self> {
161 let items: Punctuated<OrchestraAttrItem, Token![,]> =
162 input.parse_terminated(OrchestraAttrItem::parse)?;
163
164 let mut unique = HashMap::<
165 std::mem::Discriminant<OrchestraAttrItem>,
166 OrchestraAttrItem,
167 RandomState,
168 >::default();
169 for item in items {
170 if let Some(first) = unique.insert(std::mem::discriminant(&item), item.clone()) {
171 let mut e = Error::new(
172 item.span(),
173 format!("Duplicate definition of orchestra generation type found"),
174 );
175 e.combine(Error::new(first.span(), "previously defined here."));
176 return Err(e)
177 }
178 }
179
180 let signal_channel_capacity =
181 extract_variant!(unique, SignalChannelCapacity; default = 64_usize);
182 let message_channel_capacity =
183 extract_variant!(unique, MessageChannelCapacity; default = 1024_usize);
184
185 let error = extract_variant!(unique, ExternErrorType; err = "Must declare the orchestra error type via `error=..`.")?;
186 let event = extract_variant!(unique, ExternEventType; err = "Must declare the orchestra event type via `event=..`.")?;
187 let signal = extract_variant!(unique, ExternOrchestraSignalType; err = "Must declare the orchestra signal type via `signal=..`.")?;
188 let message_wrapper = extract_variant!(unique, MessageWrapperName; err = "Must declare the orchestra generated wrapping message type via `gen=..`.")?;
189 let outgoing = extract_variant!(unique, OutgoingType);
190 let boxed_messages = extract_variant!(unique, BoxedMessages; default = false);
191
192 Ok(OrchestraAttrArgs {
193 signal_channel_capacity,
194 message_channel_capacity,
195 extern_event_ty: event,
196 extern_signal_ty: signal,
197 extern_error_ty: error,
198 outgoing_ty: outgoing,
199 message_wrapper,
200 boxed_messages,
201 })
202 }
203}