bitpiece_macros/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
mod enums;
mod named_structs;
mod newtypes;
mod utils;

use enums::bitpiece_enum;
use named_structs::bitpiece_named_struct;
use syn::{parse_macro_input, DeriveInput, LitInt};
use utils::{are_generics_empty, not_supported_err};

/// an attribute for defining bitfields.
#[proc_macro_attribute]
pub fn bitpiece(
    args: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    impl_bitpiece(args, input)
}

fn impl_bitpiece(
    args_tokens: proc_macro::TokenStream,
    input_tokens: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let maybe_explicit_bit_length = parse_macro_input!(args_tokens as Option<LitInt>);
    let explicit_bit_length: Option<usize> = match maybe_explicit_bit_length {
        Some(bit_length) => match bit_length.base10_parse() {
            Ok(parsed_bit_length) => Some(parsed_bit_length),
            Err(err) => {
                return err.into_compile_error().into();
            }
        },
        None => None,
    };
    let input = parse_macro_input!(input_tokens as DeriveInput);

    if !are_generics_empty(&input.generics) {
        return not_supported_err("generics");
    }

    match &input.data {
        syn::Data::Struct(data_struct) => match &data_struct.fields {
            syn::Fields::Named(fields) => {
                bitpiece_named_struct(&input, fields, explicit_bit_length)
            }
            syn::Fields::Unnamed(_) => not_supported_err("unnamed structs"),
            syn::Fields::Unit => not_supported_err("empty structs"),
        },
        syn::Data::Enum(data_enum) => bitpiece_enum(&input, data_enum, explicit_bit_length),
        syn::Data::Union(_) => not_supported_err("unions"),
    }
}