diman_unit_system 0.5.1

Internal procedural macros for diman.
Documentation
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned};

use super::Codegen;
use crate::types::{Constant, Unit};
use diman_lib::magnitude::Magnitude;

impl Codegen {
    pub fn gen_units_and_constants(&self) -> TokenStream {
        let def_unit_type = self.gen_unit_type();
        let units: TokenStream = self
            .defs
            .units
            .iter()
            .map(|unit| {
                let unit = self.gen_unit_def(unit);
                quote! {
                    #unit
                }
            })
            .collect();
        let constants: TokenStream = self
            .defs
            .constants
            .iter()
            .map(|unit| {
                let constant = self.gen_constant_def(unit);
                quote! {
                    #constant
                }
            })
            .collect();
        let path_prefix = self.caller_type.path_prefix();
        quote! {
            pub use #path_prefix::magnitude::Magnitude;
            mod unit_type {
                use super::Dimension;
                use super::Magnitude;
                use super::Quantity;
                #def_unit_type
            }
            #[allow(unused)]
            pub use unit_type::Unit;
            #[allow(non_upper_case_globals)]
            #[allow(unused)]
            pub mod units {
                use super::Magnitude;
                use super::Unit;
                use super::Dimension;
                use super::Exponent;
                #units
            }
            #[allow(unused)]
            pub mod constants {
                use super::Magnitude;
                use super::Unit;
                use super::Dimension;
                use super::Exponent;
                #constants
            }
        }
    }

    fn gen_unit_def(&self, unit: &Unit) -> TokenStream {
        let dimension = self.get_dimension_expr(&unit.dimensions);
        let name = &unit.name;
        let magnitude = self.get_magnitude_expr(unit.magnitude);
        let span = self.defs.dimension_type.span();
        quote_spanned! {span=>
            pub const #name: Unit<{ #dimension }, { #magnitude }> = Unit;
        }
    }

    fn gen_constant_def(&self, constant: &Constant) -> TokenStream {
        let dimension = self.get_dimension_expr(&constant.dimensions);
        let name = &constant.name;
        let magnitude = self.get_magnitude_expr(constant.magnitude);
        let span = self.defs.dimension_type.span();
        quote_spanned! {span=>
            pub const #name: Unit<{ #dimension }, { #magnitude }> = Unit;
        }
    }

    pub fn get_magnitude_expr(&self, magnitude: Magnitude) -> TokenStream {
        let (mantissa, exponent, sign) = (magnitude.mantissa, magnitude.exponent, magnitude.sign);
        quote! {
            Magnitude {
                mantissa: #mantissa,
                exponent: #exponent,
                sign: #sign,
            }
        }
    }
}