valence_protocol_macros/
lib.rs
1#![doc = include_str!("../README.md")]
2
3use proc_macro::TokenStream as StdTokenStream;
4use proc_macro2::TokenStream;
5use quote::ToTokens;
6use syn::{
7 parse_quote, Attribute, GenericParam, Generics, Lifetime, LifetimeParam, LitInt, Result,
8 Variant,
9};
10
11mod decode;
12mod encode;
13mod packet;
14
15#[proc_macro_derive(Encode, attributes(packet))]
16pub fn derive_encode(item: StdTokenStream) -> StdTokenStream {
17 match encode::derive_encode(item.into()) {
18 Ok(tokens) => tokens.into(),
19 Err(e) => e.into_compile_error().into(),
20 }
21}
22
23#[proc_macro_derive(Decode, attributes(packet))]
24pub fn derive_decode(item: StdTokenStream) -> StdTokenStream {
25 match decode::derive_decode(item.into()) {
26 Ok(tokens) => tokens.into(),
27 Err(e) => e.into_compile_error().into(),
28 }
29}
30
31#[proc_macro_derive(Packet, attributes(packet))]
32pub fn derive_packet(item: StdTokenStream) -> StdTokenStream {
33 match packet::derive_packet(item.into()) {
34 Ok(tokens) => tokens.into(),
35 Err(e) => e.into_compile_error().into(),
36 }
37}
38
39fn pair_variants_with_discriminants(
40 variants: impl IntoIterator<Item = Variant>,
41) -> Result<Vec<(i32, Variant)>> {
42 let mut discriminant = 0;
43 variants
44 .into_iter()
45 .map(|v| {
46 if let Some(i) = parse_tag_attr(&v.attrs)? {
47 discriminant = i;
48 }
49
50 let pair = (discriminant, v);
51 discriminant += 1;
52 Ok(pair)
53 })
54 .collect::<Result<_>>()
55}
56
57fn parse_tag_attr(attrs: &[Attribute]) -> Result<Option<i32>> {
58 for attr in attrs {
59 if attr.path().is_ident("packet") {
60 let mut res = 0;
61
62 attr.parse_nested_meta(|meta| {
63 if meta.path.is_ident("tag") {
64 res = meta.value()?.parse::<LitInt>()?.base10_parse::<i32>()?;
65 Ok(())
66 } else {
67 Err(meta.error("unrecognized argument"))
68 }
69 })?;
70
71 return Ok(Some(res));
72 }
73 }
74
75 Ok(None)
76}
77
78fn decode_split_for_impl(
82 mut generics: Generics,
83 lifetime: Lifetime,
84) -> (TokenStream, TokenStream, TokenStream) {
85 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
86
87 let mut impl_generics = impl_generics.to_token_stream();
88 let ty_generics = ty_generics.to_token_stream();
89 let where_clause = where_clause.to_token_stream();
90
91 if generics.lifetimes().next().is_none() {
92 generics
93 .params
94 .push(GenericParam::Lifetime(LifetimeParam::new(lifetime)));
95
96 impl_generics = generics.split_for_impl().0.to_token_stream();
97 }
98
99 (impl_generics, ty_generics, where_clause)
100}
101
102fn add_trait_bounds(generics: &mut Generics, trait_: TokenStream) {
103 for param in &mut generics.params {
104 if let GenericParam::Type(type_param) = param {
105 type_param.bounds.push(parse_quote!(#trait_))
106 }
107 }
108}