orchestra_proc_macro/parse/
parse_orchestra_struct.rs

1// Copyright (C) 2021 Parity Technologies (UK) Ltd.
2// SPDX-License-Identifier: Apache-2.0
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::parse_cfg::*;
17use itertools::Itertools;
18use proc_macro2::{Span, TokenStream};
19use quote::{quote, ToTokens};
20use std::{
21	borrow::Borrow,
22	collections::{hash_map::RandomState, HashMap, HashSet},
23};
24use syn::{
25	parenthesized,
26	parse::{Parse, ParseStream},
27	punctuated::Punctuated,
28	spanned::Spanned,
29	token,
30	token::Bracket,
31	AngleBracketedGenericArguments, AttrStyle, Error, Field, FieldsNamed, GenericArgument,
32	GenericParam, Ident, ItemStruct, LitInt, Path, PathArguments, PathSegment, Result, Token, Type,
33	TypePath, Visibility,
34};
35
36mod kw {
37	syn::custom_keyword!(wip);
38	syn::custom_keyword!(blocking);
39	syn::custom_keyword!(consumes);
40	syn::custom_keyword!(sends);
41	syn::custom_keyword!(message_capacity);
42	syn::custom_keyword!(signal_capacity);
43	syn::custom_keyword!(can_receive_priority_messages);
44}
45
46#[derive(Clone, Debug)]
47pub(crate) enum SubSysAttrItem {
48	/// The subsystem is still a work in progress
49	/// and should not be communicated with.
50	Wip(kw::wip),
51	/// The subsystem is blocking and requires to be
52	/// spawned on an exclusive thread.
53	Blocking(kw::blocking),
54	/// Message to be sent by this subsystem.
55	Sends(Sends),
56	/// Message to be consumed by this subsystem.
57	Consumes(Consumes),
58	/// Custom message channels capacity for this subsystem
59	MessageChannelCapacity(ChannelCapacity<kw::message_capacity>),
60	/// Custom signal channels capacity for this subsystem
61	SignalChannelCapacity(ChannelCapacity<kw::signal_capacity>),
62	/// The subsystem can receive priority messages
63	CanReceivePriorityMessages(kw::can_receive_priority_messages),
64}
65
66impl Parse for SubSysAttrItem {
67	fn parse(input: ParseStream) -> Result<Self> {
68		let lookahead = input.lookahead1();
69		Ok(if lookahead.peek(kw::wip) {
70			Self::Wip(input.parse::<kw::wip>()?)
71		} else if lookahead.peek(kw::blocking) {
72			Self::Blocking(input.parse::<kw::blocking>()?)
73		} else if lookahead.peek(kw::sends) {
74			Self::Sends(input.parse::<Sends>()?)
75		} else if lookahead.peek(kw::message_capacity) {
76			Self::MessageChannelCapacity(input.parse::<ChannelCapacity<kw::message_capacity>>()?)
77		} else if lookahead.peek(kw::signal_capacity) {
78			Self::SignalChannelCapacity(input.parse::<ChannelCapacity<kw::signal_capacity>>()?)
79		} else if lookahead.peek(kw::can_receive_priority_messages) {
80			Self::CanReceivePriorityMessages(input.parse::<kw::can_receive_priority_messages>()?)
81		} else {
82			Self::Consumes(input.parse::<Consumes>()?)
83		})
84	}
85}
86
87impl ToTokens for SubSysAttrItem {
88	fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
89		let ts = match self {
90			Self::Wip(wip) => {
91				quote! { #wip }
92			},
93			Self::Blocking(blocking) => {
94				quote! { #blocking }
95			},
96			Self::Sends(_) => {
97				quote! {}
98			},
99			Self::Consumes(_) => {
100				quote! {}
101			},
102			Self::MessageChannelCapacity(_) => {
103				quote! {}
104			},
105			Self::SignalChannelCapacity(_) => {
106				quote! {}
107			},
108			Self::CanReceivePriorityMessages(can_receive_priority_messages) => {
109				quote! { #can_receive_priority_messages }
110			},
111		};
112		tokens.extend(ts.into_iter());
113	}
114}
115
116/// A field of the struct annotated with
117/// `#[subsystem(A, B, C)]`
118#[derive(Clone, Debug)]
119pub(crate) struct SubSysField {
120	/// Name of the field.
121	pub(crate) name: Ident,
122	/// Generate generic type name for the `AllSubsystems` type
123	/// which is also used `#wrapper_message :: #variant` variant
124	/// part.
125	pub(crate) generic: Ident,
126	/// Type of message to be consumed by the subsystem.
127	pub(crate) message_to_consume: Option<Path>,
128	/// Types of messages to be sent by the subsystem.
129	pub(crate) messages_to_send: Vec<Path>,
130	/// If the subsystem implementation is blocking execution and hence
131	/// has to be spawned on a separate thread or thread pool.
132	pub(crate) blocking: bool,
133	/// The subsystem is a work in progress.
134	/// Avoids dispatching `Wrapper` type messages, but generates the variants.
135	/// Does not require the subsystem to be instantiated with the builder pattern.
136	pub(crate) wip: bool,
137	/// Custom message channel capacity
138	pub(crate) message_capacity: Option<usize>,
139	/// Custom signal channel capacity
140	pub(crate) signal_capacity: Option<usize>,
141	/// The subsystem can receive priority messages
142	pub(crate) can_receive_priority_messages: bool,
143
144	pub(crate) feature_gates: Option<CfgPredicate>,
145}
146
147impl SubSysField {
148	pub(crate) fn dummy_msg_name(&self) -> Ident {
149		Ident::new(format!("{}Message", self.generic).as_str(), self.name.span())
150	}
151
152	/// Returns either the specified to be consumed messsage
153	/// or the generated dummy message.
154	pub(crate) fn message_to_consume(&self) -> Path {
155		if let Some(ref consumes) = self.message_to_consume {
156			consumes.clone()
157		} else {
158			Path::from(self.dummy_msg_name())
159		}
160	}
161
162	/// Generate the dummy message type if the subsystem does not consume one
163	///
164	/// Note: Only required to the internal structure anchoring everything to
165	/// the consuming message type. See #11 for a full solution.
166	pub(crate) fn gen_dummy_message_ty(&self) -> TokenStream {
167		if self.message_to_consume.is_none() {
168			let dummy_msg_ident = self.dummy_msg_name();
169			quote! {
170				#[doc =
171				r###"A dummy implementation to satisfy the current internal structure
172			and cannot be constructed delibarately, since it's not meant to be sent or used at all"###]
173				#[derive(Debug, Clone, Copy)]
174				pub enum #dummy_msg_ident {}
175			}
176		} else {
177			TokenStream::new()
178		}
179	}
180}
181
182// Converts a type enum to a path if this type is a TypePath
183fn try_type_to_path(ty: &Type, span: Span) -> Result<Path> {
184	match ty {
185		Type::Path(path) => Ok(path.path.clone()),
186		_ => Err(Error::new(span, "Type must be a path expression.")),
187	}
188}
189
190// Converts a Rust type to a list of idents recursively checking the possible values
191fn flatten_type(ty: &Type, span: Span) -> Result<Vec<Ident>> {
192	match ty {
193		syn::Type::Array(ar) => flatten_type(&ar.elem, span),
194		syn::Type::Paren(par) => flatten_type(&par.elem, span),
195		syn::Type::Path(type_path) => type_path
196			.path
197			.segments
198			.iter()
199			.map(|seg| flatten_path_segments(seg, span.clone()))
200			.flatten_ok()
201			.collect::<Result<Vec<_>>>(),
202		syn::Type::Tuple(tup) => tup
203			.elems
204			.iter()
205			.map(|element| flatten_type(element, span.clone()))
206			.flatten_ok()
207			.collect::<Result<Vec<_>>>(),
208		_ => Err(Error::new(span, format!("Unsupported type: {:?}", ty))),
209	}
210}
211
212// Flatten segments of some path to a list of idents used in these segments
213fn flatten_path_segments(path_segment: &PathSegment, span: Span) -> Result<Vec<Ident>> {
214	let mut result = vec![path_segment.ident.clone()];
215
216	match &path_segment.arguments {
217		syn::PathArguments::AngleBracketed(args) => {
218			let mut recursive_idents = args
219				.args
220				.iter()
221				.map(|generic_argument| match generic_argument {
222					syn::GenericArgument::Type(ty) => flatten_type(ty, span.clone()),
223					_ => Err(Error::new(
224						span,
225						format!(
226							"Field has a generic with an unsupported parameter {:?}",
227							generic_argument
228						),
229					)),
230				})
231				.flatten_ok()
232				.collect::<Result<Vec<_>>>()?;
233			result.append(&mut recursive_idents);
234		},
235		syn::PathArguments::None => {},
236		_ =>
237			return Err(Error::new(
238				span,
239				format!(
240					"Field has a generic with an unsupported path {:?}",
241					path_segment.arguments
242				),
243			)),
244	}
245
246	Ok(result)
247}
248
249macro_rules! extract_variant {
250	($unique:expr, $variant:ident ; default = $fallback:expr) => {
251		extract_variant!($unique, $variant).unwrap_or_else(|| $fallback)
252	};
253	($unique:expr, $variant:ident ; err = $err:expr) => {
254		extract_variant!($unique, $variant).ok_or_else(|| Error::new(Span::call_site(), $err))
255	};
256	($unique:expr, $variant:ident take) => {
257		$unique.values().find_map(|item| {
258			if let SubSysAttrItem::$variant(value) = item {
259				Some(value.clone())
260			} else {
261				None
262			}
263		})
264	};
265	($unique:expr, $variant:ident) => {
266		$unique.values().find_map(|item| {
267			if let SubSysAttrItem::$variant(_) = item {
268				Some(true)
269			} else {
270				None
271			}
272		})
273	};
274}
275
276#[derive(Debug, Clone)]
277pub(crate) struct Sends {
278	#[allow(dead_code)]
279	pub(crate) keyword_sends: kw::sends,
280	#[allow(dead_code)]
281	pub(crate) colon: Token![:],
282	#[allow(dead_code)]
283	pub(crate) bracket: Option<Bracket>,
284	pub(crate) sends: Punctuated<Path, Token![,]>,
285}
286
287impl Parse for Sends {
288	fn parse(input: syn::parse::ParseStream) -> Result<Self> {
289		let content;
290		let keyword_sends = input.parse()?;
291		let colon = input.parse()?;
292		let (bracket, sends) = if !input.peek(syn::token::Bracket) {
293			let mut sends = Punctuated::new();
294			sends.push_value(input.parse::<Path>()?);
295			(None, sends)
296		} else {
297			let bracket = Some(syn::bracketed!(content in input));
298			let sends = Punctuated::parse_terminated(&content)?;
299			(bracket, sends)
300		};
301		Ok(Self { keyword_sends, colon, bracket, sends })
302	}
303}
304
305#[derive(Debug, Clone)]
306pub(crate) struct Consumes {
307	#[allow(dead_code)]
308	pub(crate) keyword_consumes: Option<kw::consumes>,
309	#[allow(dead_code)]
310	pub(crate) colon: Option<Token![:]>,
311	pub(crate) consumes: Path,
312}
313
314impl Parse for Consumes {
315	fn parse(input: syn::parse::ParseStream) -> Result<Self> {
316		let lookahead = input.lookahead1();
317		Ok(if lookahead.peek(kw::consumes) {
318			Self {
319				keyword_consumes: Some(input.parse()?),
320				colon: input.parse()?,
321				consumes: input.parse()?,
322			}
323		} else {
324			Self { keyword_consumes: None, colon: None, consumes: input.parse()? }
325		})
326	}
327}
328
329#[derive(Debug, Clone)]
330pub(crate) struct ChannelCapacity<T: Parse> {
331	#[allow(dead_code)]
332	tag: T,
333	#[allow(dead_code)]
334	colon_token: token::Colon,
335	value: usize,
336}
337
338impl<T: Parse> Parse for ChannelCapacity<T> {
339	fn parse(input: syn::parse::ParseStream) -> Result<Self> {
340		Ok(Self {
341			tag: input.parse::<T>()?,
342			colon_token: input.parse()?,
343			value: input.parse::<LitInt>()?.base10_parse::<usize>()?,
344		})
345	}
346}
347
348/// Parses `(Foo, sends = [Bar, Baz])`
349/// including the `(` and `)`.
350#[derive(Debug, Clone)]
351pub(crate) struct SubSystemAttrItems {
352	/// The subsystem is in progress, only generate the `Wrapper` variant, but do not forward messages
353	/// and also not include the subsystem in the list of subsystems.
354	pub(crate) wip: bool,
355	/// If there are blocking components in the subsystem and hence it should be
356	/// spawned on a dedicated thread pool for such subssytems.
357	pub(crate) blocking: bool,
358	/// The message type being consumed by the subsystem.
359	pub(crate) consumes: Option<Consumes>,
360	pub(crate) sends: Option<Sends>,
361	/// Custom message channel capacity
362	pub(crate) message_capacity: Option<ChannelCapacity<kw::message_capacity>>,
363	/// Custom signal channel capacity
364	pub(crate) signal_capacity: Option<ChannelCapacity<kw::signal_capacity>>,
365	/// The subsystem can receive priority messages
366	pub(crate) can_receive_priority_messages: bool,
367}
368
369impl Parse for SubSystemAttrItems {
370	fn parse(input: syn::parse::ParseStream) -> Result<Self> {
371		let span = input.span();
372
373		let content;
374		let _paren_token = parenthesized!(content in input);
375
376		let items = content.call(Punctuated::<SubSysAttrItem, Token![,]>::parse_terminated)?;
377
378		let mut unique = HashMap::<
379			std::mem::Discriminant<SubSysAttrItem>,
380			SubSysAttrItem,
381			RandomState,
382		>::default();
383
384		for item in items {
385			if let Some(first) = unique.insert(std::mem::discriminant(&item), item.clone()) {
386				let mut e =
387					Error::new(item.span(), "Duplicate definition of subsystem attribute found");
388				e.combine(Error::new(first.span(), "previously defined here."));
389				return Err(e)
390			}
391		}
392
393		// A subsystem makes no sense if not one of them is provided
394		let sends = extract_variant!(unique, Sends take);
395		let consumes = extract_variant!(unique, Consumes take);
396		if sends.as_ref().map(|sends| sends.sends.is_empty()).unwrap_or(true) && consumes.is_none()
397		{
398			return Err(Error::new(
399				span,
400				"Must have at least one of `consumes: [..]` and `sends: [..]`.",
401			))
402		}
403
404		let blocking = extract_variant!(unique, Blocking; default = false);
405		let wip = extract_variant!(unique, Wip; default = false);
406		let message_capacity = extract_variant!(unique, MessageChannelCapacity take );
407		let signal_capacity = extract_variant!(unique, SignalChannelCapacity take );
408		let can_receive_priority_messages =
409			extract_variant!(unique, CanReceivePriorityMessages; default = false);
410
411		Ok(Self {
412			blocking,
413			wip,
414			sends,
415			consumes,
416			message_capacity,
417			signal_capacity,
418			can_receive_priority_messages,
419		})
420	}
421}
422
423/// Fields that are _not_ subsystems.
424#[derive(Debug, Clone)]
425pub(crate) struct BaggageField {
426	pub(crate) field_name: Ident,
427	pub(crate) field_ty: Type,
428	pub(crate) generic_types: Vec<Ident>,
429	pub(crate) vis: Visibility,
430}
431
432#[derive(Clone, Debug)]
433pub(crate) struct OrchestraInfo {
434	/// Where the support crate `::orchestra` lives.
435	pub(crate) support_crate: Path,
436
437	/// Fields annotated with `#[subsystem(..)]`.
438	pub(crate) subsystems: Vec<SubSysField>,
439	/// Fields that do not define a subsystem,
440	/// but are mere baggage.
441	pub(crate) baggage: Vec<BaggageField>,
442	/// Name of the wrapping enum for all messages, defaults to `AllMessages`.
443	pub(crate) message_wrapper: Ident,
444	/// Name of the orchestra struct, used as a prefix for
445	/// almost all generated types.
446	pub(crate) orchestra_name: Ident,
447
448	/// Size of the bounded channel.
449	pub(crate) message_channel_capacity: usize,
450	/// Size of the bounded signal channel.
451	pub(crate) signal_channel_capacity: usize,
452	/// Box messages that are sent to the subsystems.
453	pub(crate) boxed_messages: bool,
454
455	/// Signals to be sent, sparse information that is used intermittently.
456	pub(crate) extern_signal_ty: Path,
457
458	/// Incoming event type from the outer world, usually an external framework of some sort.
459	pub(crate) extern_event_ty: Path,
460
461	/// Type of messages that are sent to an external subsystem.
462	/// Merely here to be included during generation of `#message_wrapper` type.
463	pub(crate) outgoing_ty: Option<Path>,
464
465	/// Incoming event type from the outer world, commonly from the network.
466	pub(crate) extern_error_ty: Path,
467}
468
469/// Configuration set for builder generation.
470pub(crate) struct SubsystemConfigSet<'a> {
471	/// These subsystems should be enabled for this config set.
472	pub(crate) enabled_subsystems: Vec<&'a SubSysField>,
473
474	/// Feature gate that is used to conditionally include
475	/// the subsystems included in `enabled_subsystems`.
476	pub(crate) feature_gate: TokenStream,
477}
478
479impl<'a> SubsystemConfigSet<'a> {
480	pub(crate) fn subsystem_names_without_wip(&self) -> Vec<Ident> {
481		subsystem_names_without_wip(&self.enabled_subsystems)
482	}
483
484	pub(crate) fn subsystem_generic_types(&self) -> Vec<Ident> {
485		subsystem_generic_types(&self.enabled_subsystems)
486	}
487
488	pub(crate) fn channel_names_without_wip(
489		&self,
490		suffix: impl Into<Option<&'static str>>,
491	) -> Vec<Ident> {
492		channel_names_without_wip(&self.enabled_subsystems, suffix)
493	}
494
495	pub(crate) fn consumes_without_wip(&self) -> Vec<Path> {
496		consumes_without_wip(&self.enabled_subsystems)
497	}
498
499	pub(crate) fn message_channel_capacities_without_wip(
500		&self,
501		default_capacity: usize,
502	) -> Vec<LitInt> {
503		message_channel_capacities_without_wip(&self.enabled_subsystems, default_capacity)
504	}
505
506	pub(crate) fn signal_channel_capacities_without_wip(
507		&self,
508		default_capacity: usize,
509	) -> Vec<LitInt> {
510		signal_channel_capacities_without_wip(&self.enabled_subsystems, default_capacity)
511	}
512
513	pub(crate) fn can_receive_priority_messages_without_wip(&self) -> Vec<syn::LitBool> {
514		can_receive_priority_messages_without_wip(&self.enabled_subsystems)
515	}
516}
517
518impl OrchestraInfo {
519	pub(crate) fn support_crate_name(&self) -> &Path {
520		&self.support_crate
521	}
522
523	pub(crate) fn variant_names(&self) -> Vec<Ident> {
524		self.subsystems.iter().map(|ssf| ssf.generic.clone()).collect::<Vec<_>>()
525	}
526
527	pub(crate) fn variant_names_without_wip(&self) -> Vec<Ident> {
528		self.subsystems
529			.iter()
530			.filter(|ssf| !ssf.wip)
531			.map(|ssf| ssf.generic.clone())
532			.collect::<Vec<_>>()
533	}
534
535	pub(crate) fn variant_names_only_wip(&self) -> Vec<Ident> {
536		self.subsystems
537			.iter()
538			.filter(|ssf| ssf.wip)
539			.map(|ssf| ssf.generic.clone())
540			.collect::<Vec<_>>()
541	}
542
543	pub(crate) fn subsystems(&self) -> &[SubSysField] {
544		self.subsystems.as_slice()
545	}
546
547	pub(crate) fn feature_gates(&self) -> Vec<TokenStream> {
548		self.subsystems
549			.iter()
550			.map(|s| s.feature_gates.clone().map_or(quote! {}, |fg| quote! { #[cfg(#fg)] }))
551			.collect::<Vec<_>>()
552	}
553
554	/// Generates all mutually exclusive feature combinations.
555	///	For each feature combination, finds the subsystems
556	///	that should be enabled by this combination.
557	pub(crate) fn feature_gated_subsystem_sets(&self) -> Vec<SubsystemConfigSet> {
558		// Build the powerset of all defined features.
559		// Example:
560		// [Some(f1), Some(f2), None] -> [[] [Some(f1)], [Some(f2)], [Some(f1), Some(f2)]]
561		let features_raw_powerset = self
562			.subsystems
563			.iter()
564			.filter_map(|s| s.feature_gates.clone())
565			// We assume that the feature gates are already sorted internally
566			.unique()
567			.powerset()
568			.collect_vec();
569
570		// Iterate from front and back to build mutually exclusive feature sets.
571		let res = features_raw_powerset
572			.iter()
573			.zip(features_raw_powerset.iter().rev())
574			.map(|(enabled_cfgs, disabled_cfgs)| {
575				// Create tokenstream to active this specific set of feature combinations
576				let output_feature_gate = if disabled_cfgs.is_empty() {
577					quote! { #[cfg(all(#(#enabled_cfgs),*))] }
578				} else {
579					quote! { #[cfg(all(#(#enabled_cfgs,)* not(any(#(#disabled_cfgs),*))))] }
580				};
581
582				let enabled = self
583					.subsystems
584					.iter()
585					.filter(|subsys| {
586						// Subsystems without a feature gate should always be included.
587						// If they have a feature gate, check if it is part of the currently activated feature sets.
588						subsys
589							.feature_gates
590							.as_ref()
591							.map_or(true, |cfg| enabled_cfgs.contains(&cfg))
592					})
593					.collect();
594
595				SubsystemConfigSet {
596					enabled_subsystems: enabled,
597					feature_gate: output_feature_gate,
598				}
599			})
600			.collect();
601		res
602	}
603
604	pub(crate) fn subsystem_names_without_wip(&self) -> Vec<Ident> {
605		subsystem_names_without_wip(&self.subsystems)
606	}
607
608	pub(crate) fn baggage(&self) -> &[BaggageField] {
609		self.baggage.as_slice()
610	}
611
612	pub(crate) fn baggage_names(&self) -> Vec<Ident> {
613		self.baggage.iter().map(|bag| bag.field_name.clone()).collect::<Vec<_>>()
614	}
615	pub(crate) fn baggage_decl(&self) -> Vec<TokenStream> {
616		self.baggage
617			.iter()
618			.map(|bag| {
619				let BaggageField { vis, field_ty, field_name, .. } = bag;
620				quote! { #vis #field_name: #field_ty }
621			})
622			.collect::<Vec<TokenStream>>()
623	}
624
625	pub(crate) fn baggage_generic_types(&self) -> Vec<Ident> {
626		self.baggage
627			.iter()
628			.flat_map(|bag| bag.generic_types.clone())
629			.collect::<Vec<_>>()
630	}
631
632	pub(crate) fn any_message(&self) -> Vec<Path> {
633		self.subsystems.iter().map(|ssf| ssf.message_to_consume()).collect::<Vec<_>>()
634	}
635
636	pub(crate) fn channel_names_without_wip(
637		&self,
638		suffix: impl Into<Option<&'static str>>,
639	) -> Vec<Ident> {
640		channel_names_without_wip(&self.subsystems, suffix)
641	}
642
643	pub(crate) fn consumes_without_wip(&self) -> Vec<Path> {
644		consumes_without_wip(&self.subsystems)
645	}
646
647	pub(crate) fn box_message_if_needed(&self, message_ty: &Path, span: Span) -> Path {
648		if self.boxed_messages {
649			let mut boxed_message = PathSegment::from(Ident::new("Box", span.clone()));
650			boxed_message.arguments =
651				PathArguments::AngleBracketed(AngleBracketedGenericArguments {
652					colon2_token: None,
653					lt_token: Token![<](span.clone()),
654					args: Punctuated::from_iter(std::iter::once(GenericArgument::Type(
655						Type::Path(TypePath { path: message_ty.clone(), qself: None }),
656					))),
657					gt_token: Token![>](span.clone()),
658				});
659			Path::from(boxed_message)
660		} else {
661			message_ty.clone()
662		}
663	}
664}
665
666/// Internals of the orchestra.
667#[derive(Debug, Clone)]
668pub(crate) struct OrchestraGuts {
669	pub(crate) name: Ident,
670	pub(crate) subsystems: Vec<SubSysField>,
671	pub(crate) baggage: Vec<BaggageField>,
672}
673
674impl OrchestraGuts {
675	pub(crate) fn parse_fields(
676		name: Ident,
677		baggage_generics: HashSet<Ident>,
678		fields: FieldsNamed,
679	) -> Result<Self> {
680		let n = fields.named.len();
681		let mut subsystems = Vec::with_capacity(n);
682		let mut baggage = Vec::with_capacity(n);
683
684		// The types of `#[subsystem(..)]` annotated fields
685		// have to be unique, since they are used as generics
686		// for the builder pattern besides other places.
687		let mut unique_subsystem_idents = HashSet::<Ident>::new();
688		for Field { attrs, vis, ident, ty, .. } in fields.named.into_iter() {
689			// collect all subsystem annotations per field
690			let mut subsystem_attr =
691				attrs.iter().filter(|attr| attr.style == AttrStyle::Outer).filter_map(|attr| {
692					let span = attr.path.span();
693					attr.path.get_ident().filter(|ident| *ident == "subsystem").map(move |_ident| {
694						let attr_tokens = attr.tokens.clone();
695						(attr_tokens, span)
696					})
697				});
698
699			let cfg_attr =
700				attrs.iter().filter(|attr| attr.style == AttrStyle::Outer).filter_map(|attr| {
701					let span = attr.path.span();
702					attr.path.get_ident().filter(|ident| *ident == "cfg").map(move |_ident| {
703						let attr_tokens = attr.tokens.clone();
704
705						(attr_tokens, span)
706					})
707				});
708
709			let mut feature_gates: Option<CfgPredicate> = None;
710			for (cfg_token_stream, _span) in cfg_attr {
711				let cfg_predicate = syn::parse2::<CfgExpressionRoot>(cfg_token_stream)?.predicate;
712				feature_gates = match feature_gates {
713					Some(cfg) => Some(cfg.merge(cfg_predicate)),
714					None => Some(cfg_predicate),
715				};
716			}
717			// Sort here so we can do easy equality checks later
718			feature_gates.iter_mut().for_each(CfgPredicate::sort_recursive);
719
720			let ident = ident.ok_or_else(|| {
721				Error::new(
722					ty.span(),
723					"Missing identifier for field, only named fields are expected.",
724				)
725			})?;
726
727			if let Some((attr_tokens, span)) = subsystem_attr.next() {
728				// a `#[subsystem(..)]` annotation exists
729				if let Some((_attr_tokens2, span2)) = subsystem_attr.next() {
730					return Err({
731						let mut err = Error::new(span, "The first subsystem annotation is at");
732						err.combine(Error::new(span2, "but another here for the same field."));
733						err
734					})
735				}
736
737				let span = attr_tokens.span();
738
739				let attr_tokens = attr_tokens.clone();
740				let subsystem_attrs: SubSystemAttrItems = syn::parse2(attr_tokens.clone())?;
741
742				let field_ty = try_type_to_path(&ty, span)?;
743				let generic = field_ty
744					.get_ident()
745					.ok_or_else(|| {
746						Error::new(
747							field_ty.span(),
748							"Must be an identifier, not a path. It will be used as a generic.",
749						)
750					})?
751					.clone();
752				// check for unique subsystem name, otherwise we'd create invalid code:
753				if let Some(previous) = unique_subsystem_idents.get(&generic) {
754					let mut e = Error::new(generic.span(), "Duplicate subsystem names");
755					e.combine(Error::new(previous.span(), "previously defined here."));
756					return Err(e)
757				}
758				unique_subsystem_idents.insert(generic.clone());
759
760				let SubSystemAttrItems {
761					wip,
762					blocking,
763					consumes,
764					sends,
765					message_capacity,
766					signal_capacity,
767					can_receive_priority_messages,
768					..
769				} = subsystem_attrs;
770
771				// messages to be sent
772				let sends = if let Some(sends) = sends {
773					Vec::from_iter(sends.sends.iter().cloned())
774				} else {
775					vec![]
776				};
777				let consumes = consumes.map(|consumes| consumes.consumes);
778				let message_capacity = message_capacity.map(|capacity| capacity.value);
779				let signal_capacity = signal_capacity.map(|capacity| capacity.value);
780
781				subsystems.push(SubSysField {
782					name: ident,
783					generic,
784					message_to_consume: consumes,
785					messages_to_send: sends,
786					wip,
787					blocking,
788					message_capacity,
789					signal_capacity,
790					feature_gates,
791					can_receive_priority_messages,
792				});
793			} else {
794				// collect the "baggage"
795				let flattened = flatten_type(&ty, ident.span())?;
796				let generic_types = flattened
797					.iter()
798					.filter(|flat_ident| baggage_generics.contains(flat_ident))
799					.cloned()
800					.collect::<Vec<_>>();
801				baggage.push(BaggageField { field_name: ident, generic_types, field_ty: ty, vis });
802			}
803		}
804		Ok(Self { name, subsystems, baggage })
805	}
806}
807
808impl Parse for OrchestraGuts {
809	fn parse(input: ParseStream) -> Result<Self> {
810		let ds: ItemStruct = input.parse()?;
811		match ds.fields {
812			syn::Fields::Named(named) => {
813				let name = ds.ident.clone();
814
815				// collect the independent subsystem generics
816				// which need to be carried along, there are the non-generated ones
817				let mut orig_generics = ds.generics;
818
819				// remove defaults from types
820				let mut baggage_generic_idents = HashSet::with_capacity(orig_generics.params.len());
821				orig_generics.params = orig_generics
822					.params
823					.into_iter()
824					.map(|mut generic| {
825						match generic {
826							GenericParam::Type(ref mut param) => {
827								baggage_generic_idents.insert(param.ident.clone());
828								param.eq_token = None;
829								param.default = None;
830							},
831							_ => {},
832						}
833						generic
834					})
835					.collect();
836
837				Self::parse_fields(name, baggage_generic_idents, named)
838			},
839			syn::Fields::Unit => Err(Error::new(
840				ds.fields.span(),
841				"Must be a struct with named fields. Not an unit struct.",
842			)),
843			syn::Fields::Unnamed(unnamed) => Err(Error::new(
844				unnamed.span(),
845				"Must be a struct with named fields. Not an unnamed fields struct.",
846			)),
847		}
848	}
849}
850
851pub(crate) fn subsystem_names_without_wip<'a, T: Borrow<SubSysField>>(
852	subsystems: &[T],
853) -> Vec<Ident> {
854	subsystems
855		.iter()
856		.map(|e| e.borrow())
857		.filter(|ssf| !ssf.wip)
858		.map(|ssf| ssf.name.clone())
859		.collect::<Vec<_>>()
860}
861
862pub(crate) fn subsystem_generic_types<'a, T: Borrow<SubSysField>>(subsystems: &[T]) -> Vec<Ident> {
863	subsystems
864		.iter()
865		.map(|e| e.borrow())
866		.filter(|ssf| !ssf.wip)
867		.map(|ssf| ssf.generic.clone())
868		.collect::<Vec<_>>()
869}
870
871pub(crate) fn channel_names_without_wip<'a, T: Borrow<SubSysField>>(
872	subsystems: &[T],
873	suffix: impl Into<Option<&'static str>>,
874) -> Vec<Ident> {
875	let suffix = suffix.into().unwrap_or("");
876	subsystems
877		.iter()
878		.map(|e| e.borrow())
879		.filter(|ssf| !ssf.wip)
880		.map(|ssf| Ident::new(&(ssf.name.to_string() + suffix), ssf.name.span()))
881		.collect::<Vec<_>>()
882}
883
884pub(crate) fn message_channel_capacities_without_wip(
885	subsystems: &Vec<&SubSysField>,
886	default_capacity: usize,
887) -> Vec<LitInt> {
888	subsystems
889		.iter()
890		.filter(|ssf| !ssf.wip)
891		.map(|ssf| {
892			LitInt::new(
893				&(ssf.message_capacity.unwrap_or(default_capacity).to_string()),
894				ssf.message_capacity.span(),
895			)
896		})
897		.collect::<Vec<_>>()
898}
899
900pub(crate) fn signal_channel_capacities_without_wip(
901	subsystems: &Vec<&SubSysField>,
902	default_capacity: usize,
903) -> Vec<LitInt> {
904	subsystems
905		.iter()
906		.filter(|ssf| !ssf.wip)
907		.map(|ssf| {
908			LitInt::new(
909				&(ssf.signal_capacity.unwrap_or(default_capacity).to_string()),
910				ssf.signal_capacity.span(),
911			)
912		})
913		.collect::<Vec<_>>()
914}
915
916pub(crate) fn consumes_without_wip<'a, T: Borrow<SubSysField>>(subsystems: &[T]) -> Vec<Path> {
917	subsystems
918		.iter()
919		.map(|e| e.borrow())
920		.filter(|ssf| !ssf.wip)
921		.map(|ssf| ssf.message_to_consume())
922		.collect::<Vec<_>>()
923}
924
925pub(crate) fn can_receive_priority_messages_without_wip(
926	subsystems: &Vec<&SubSysField>,
927) -> Vec<syn::LitBool> {
928	subsystems
929		.iter()
930		.filter(|ssf| !ssf.wip)
931		.map(|ssf| syn::LitBool::new(ssf.can_receive_priority_messages, ssf.name.span()))
932		.collect::<Vec<_>>()
933}