le_stream_derive/lib.rs
1//! Derive macros for `le-stream`.
2//!
3//! The macros implement `le_stream::FromLeStream` and
4//! `le_stream::ToLeStream` for structs and explicitly represented enums.
5//!
6//! Struct fields are encoded in declaration order. Enum variants require
7//! `#[repr(T)]` and an explicit discriminant on every variant; the discriminant
8//! is encoded as `T`, followed by the byte representation of any associated
9//! fields.
10
11use from_le_stream::from_le_stream;
12use proc_macro2::Ident;
13use syn::{DeriveInput, GenericParam, Generics, TypeParamBound};
14use to_le_stream::to_le_stream;
15
16mod from_le_stream;
17mod to_le_stream;
18
19/// Derives `le_stream::FromLeStream` for a struct or represented enum.
20///
21/// For structs, fields are decoded in declaration order. For enums, the input
22/// stream starts with the `#[repr(T)]` discriminant. Unknown discriminants return
23/// [`None`](Option::None).
24#[proc_macro_derive(FromLeStream)]
25pub fn derive_from_le_stream(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
26 from_le_stream(input)
27}
28
29/// Derives `le_stream::ToLeStream` for a struct or represented enum.
30///
31/// For enums, the generated implementation writes the variant's declared
32/// discriminant using the enum's `#[repr(T)]` type before serializing associated
33/// fields.
34#[proc_macro_derive(ToLeStream)]
35pub fn derive_to_le_stream(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
36 to_le_stream(input)
37}
38
39fn add_trait_bounds(mut generics: Generics, trait_name: &TypeParamBound) -> Generics {
40 for param in &mut generics.params {
41 if let GenericParam::Type(ref mut type_param) = *param {
42 type_param.bounds.push(trait_name.clone());
43 }
44 }
45 generics
46}
47
48fn get_repr_type(input: &DeriveInput) -> Option<Ident> {
49 input
50 .attrs
51 .iter()
52 .filter(|attr| attr.path().is_ident("repr"))
53 .find_map(|attr| attr.parse_args().ok())
54}