composint-macro 0.1.0

Space efficient structs using otherwise useless bits
Documentation
use quote::format_ident;
use syn::{token, Ident, braced, Token};
use syn::parse::{Parse, ParseStream, Result};
use syn::punctuated::Punctuated;

use crate::sign::Sign;

use super::field::Field;

pub(crate) struct Data {
    _struct_token: Token![struct],
    pub(crate) type_name: Ident,
    _paren: token::Brace,
    pub(crate) fields: Punctuated<Field, Token![,]>,
}

impl Parse for Data {
    fn parse(input: ParseStream) -> Result<Self> {
        let content;

        Ok(Data {
            _struct_token: input.parse()?,
            type_name: input.parse()?,
            _paren: braced!(content in input),
            fields: content.parse_terminated(Field::parse, Token![,])?,
        })
    }
}

impl Data {
    pub fn field_count(&self) -> usize {
        self.fields.len()
    }

    pub fn field_names(&self) -> Vec<Ident> {
        self
            .fields
            .pairs()
            .map(|p| p.value().name.clone())
            .collect()
    }

    pub fn field_sizes(&self) -> Vec<usize> {
        self
            .fields
            .pairs()
            .map(|p| p.value().bits.base10_parse().unwrap())
            .collect()
    }

    pub fn field_types(&self) -> Vec<Ident> {
        self
            .fields
            .pairs()
            .map(|p| {
                let size = p.value().bits.base10_parse().unwrap_or(32usize);
                let sign = p.value().sign;
                (size, sign)
            })
            .map(smallest_fitting_type)
            .collect()
    }

    pub fn field_cumulative_offsets(&self) -> Vec<usize> {
        self
            .fields
            .pairs()
            .map(|p| p.value().bits.base10_parse::<usize>().unwrap())
            .scan(0usize, |state, x| {
                *state += x;
                Some(*state - x)
            })
            .collect()
    }
}


fn smallest_fitting_type((bits, sign): (usize, Sign)) -> Ident {
    format_ident!("{}{}", sign.to_char(), bits.next_power_of_two())
}