fire_stream_api_codegen/
message.rs

1use crate::util::fire_api_crate;
2
3use proc_macro2::{Span, TokenStream};
4use syn::{
5	DeriveInput, Error, Ident, Generics, Attribute, TypeGenerics, WhereClause
6};
7use quote::{quote, ToTokens};
8
9
10pub(crate) fn into_expand(input: DeriveInput) -> Result<TokenStream, Error> {
11	let DeriveInput { attrs, ident, generics, .. } = input;
12
13	let attr = MsgAttribute::from_attrs(&attrs)?;
14	let encdec_module = attr.module;
15
16	let fire = fire_api_crate()?;
17	let message = quote!(#fire::message);
18
19	let (impl_generics, ty_generics, where_clause) = split_generics(
20		&generics,
21		&fire
22	);
23
24	Ok(quote!(
25		impl #impl_generics #message::IntoMessage<A, B> for #ident #ty_generics
26		#where_clause {
27			fn into_message(
28				self
29			) -> std::result::Result<
30				#message::Message<A, B>,
31				#fire::error::MessageError
32			> {
33				#fire::encdec::#encdec_module::encode(self)
34			}
35		}
36	))
37}
38
39pub(crate) fn from_expand(input: DeriveInput) -> Result<TokenStream, Error> {
40	let DeriveInput { attrs, ident, generics, .. } = input;
41
42	let attr = MsgAttribute::from_attrs(&attrs)?;
43	let encdec_module = attr.module;
44
45	let fire = fire_api_crate()?;
46	let message = quote!(#fire::message);
47
48	let (impl_generics, ty_generics, where_clause) = split_generics(
49		&generics,
50		&fire
51	);
52
53	Ok(quote!(
54		impl #impl_generics #message::FromMessage<A, B> for #ident #ty_generics
55		#where_clause {
56			fn from_message(
57				msg: #message::Message<A, B>
58			) -> std::result::Result<Self, #fire::error::MessageError> {
59				#fire::encdec::#encdec_module::decode(msg)
60			}
61		}
62	))
63}
64
65
66struct MsgAttribute {
67	/// which module should be used to convert the types
68	pub module: Ident
69}
70
71impl MsgAttribute {
72	pub fn from_attrs(attrs: &[Attribute]) -> Result<Self, Error> {
73		let mut module = None;
74
75		for attr in attrs {
76			if !attr.path().is_ident("message") {
77				continue
78			}
79
80			module = Some(attr.parse_args()?);
81		}
82
83		Ok(Self {
84			module: module.ok_or_else(|| Error::new(
85				Span::call_site(),
86				"need an attribute #[message(..)]"
87			))?
88		})
89	}
90}
91
92fn split_generics<'a>(
93	generics: &'a Generics,
94	fire: &TokenStream
95) -> (ImplGenerics, TypeGenerics<'a>, Option<&'a WhereClause>) {
96	let mut impl_generics = generics.clone();
97	impl_generics.params.push(
98		syn::parse2(quote!(A: #fire::message::Action)).unwrap()
99	);
100	impl_generics.params.push(
101		syn::parse2(quote!(B: #fire::message::PacketBytes)).unwrap()
102	);
103
104	let (_, ty_generics, where_clause) = generics.split_for_impl();
105	(ImplGenerics(impl_generics), ty_generics, where_clause)
106}
107
108struct ImplGenerics(Generics);
109
110impl ToTokens for ImplGenerics {
111	fn to_tokens(&self, tokens: &mut TokenStream) {
112		let (impl_generics, _, _) = self.0.split_for_impl();
113		impl_generics.to_tokens(tokens);
114	}
115}