#![cfg_attr(docsrs, feature(doc_cfg))]
use proc_macro::TokenStream;
use quote::quote;
use syn::parse_macro_input;
mod arithmetic;
mod comparison;
mod config;
mod constants;
mod conversion;
mod doc_generator;
mod finite_float;
mod finite_float_trait;
mod float_conversion;
mod fromstr_impl;
mod generator;
mod option_arithmetic;
mod result_arithmetic;
mod type_aliases;
mod unary_ops;
use arithmetic::{generate_arithmetic_impls, generate_neg_impls};
use comparison::{generate_comparison_traits, generate_concrete_comparison_traits};
use config::TypeConfig;
use constants::generate_constants;
use conversion::generate_conversion_traits;
use finite_float::{
generate_concrete_impls, generate_concrete_serde_impls, generate_concrete_structs,
};
use finite_float_trait::{generate_finite_float_impls, generate_finite_float_trait};
use float_conversion::{
generate_as_f32_primitive_methods, generate_as_f32_type_methods,
generate_as_f64_primitive_methods, generate_as_f64_type_methods,
generate_try_into_f32_type_methods,
};
use fromstr_impl::{
generate_fromstr_traits, generate_parse_error_from_impls, generate_parse_error_type,
};
use option_arithmetic::generate_option_arithmetic_impls;
use result_arithmetic::generate_result_arithmetic_impls;
use type_aliases::generate_type_aliases;
use unary_ops::{
generate_abs_impls, generate_cos_impls, generate_signum_impls, generate_sin_impls,
generate_tan_impls,
};
fn generate_common_definitions() -> proc_macro2::TokenStream {
quote! {
use core::marker::PhantomData;
use core::ops::{Add, Sub, Mul, Div, Neg};
const F64_MIN_BITS: i64 = f64::MIN.to_bits() as i64;
const F64_MAX_BITS: i64 = f64::MAX.to_bits() as i64;
const ZERO_BITS: i64 = 0.0f64.to_bits() as i64;
const F64_MIN_POSITIVE_BITS: i64 = f64::MIN_POSITIVE.to_bits() as i64;
const F64_NEG_MIN_POSITIVE_BITS: i64 = (-f64::MIN_POSITIVE).to_bits() as i64;
const ONE_BITS: i64 = 1.0f64.to_bits() as i64;
const NEG_ONE_BITS: i64 = (-1.0f64).to_bits() as i64;
const F32_MIN_BITS: i64 = (f32::MIN as f64).to_bits() as i64;
const F32_MAX_BITS: i64 = (f32::MAX as f64).to_bits() as i64;
const F32_MIN_POSITIVE_BITS: i64 = (f32::MIN_POSITIVE as f64).to_bits() as i64;
const F32_NEG_MIN_POSITIVE_BITS: i64 = ((-f32::MIN_POSITIVE) as f64).to_bits() as i64;
}
}
fn generate_error_type() -> proc_macro2::TokenStream {
quote! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum FloatError {
NaN,
PosInf,
NegInf,
OutOfRange,
NoneOperand,
}
impl core::fmt::Display for FloatError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
FloatError::NaN => write!(f, "value is NaN (Not a Number)"),
FloatError::PosInf => write!(f, "value is positive infinity"),
FloatError::NegInf => write!(f, "value is negative infinity"),
FloatError::OutOfRange => write!(f, "value is outside the valid range for this type"),
FloatError::NoneOperand => write!(f, "right-hand side operand is None in Option arithmetic"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for FloatError {}
}
}
fn generate_constraint_markers(config: &TypeConfig) -> proc_macro2::TokenStream {
let markers = config.constraints.iter().map(|constraint| {
let name = &constraint.name;
quote! {
#[doc(hidden)]
#[derive(Debug, Clone, Copy)]
pub(crate) struct #name;
}
});
quote! {
#(#markers)*
}
}
#[proc_macro]
pub fn generate_finite_float_types(input: TokenStream) -> TokenStream {
let config = parse_macro_input!(input as TypeConfig);
let mut all_code = vec![
generate_common_definitions(),
generate_error_type(),
generate_parse_error_type(),
generate_parse_error_from_impls(),
generate_constraint_markers(&config),
generate_concrete_structs(&config),
generate_comparison_traits(),
];
all_code.push(generate_concrete_impls(&config));
all_code.push(generate_concrete_serde_impls(&config));
all_code.push(generate_concrete_comparison_traits(&config));
all_code.push(generate_arithmetic_impls(&config));
all_code.push(generate_option_arithmetic_impls(&config));
all_code.push(generate_result_arithmetic_impls(&config));
all_code.push(generate_neg_impls(&config));
all_code.push(generate_abs_impls(&config));
all_code.push(generate_signum_impls(&config));
all_code.push(generate_sin_impls(&config));
all_code.push(generate_cos_impls(&config));
all_code.push(generate_tan_impls(&config));
all_code.push(generate_as_f32_primitive_methods(&config));
all_code.push(generate_as_f64_primitive_methods(&config));
all_code.push(generate_as_f32_type_methods(&config));
all_code.push(generate_as_f64_type_methods(&config));
all_code.push(generate_try_into_f32_type_methods(&config));
all_code.push(generate_conversion_traits(&config));
all_code.push(generate_fromstr_traits(&config));
all_code.push(generate_finite_float_trait(&config));
all_code.push(generate_finite_float_impls(&config));
all_code.push(generate_constants(&config));
all_code.push(generate_type_aliases(&config));
let expanded = quote! {
#(#all_code)*
};
TokenStream::from(expanded)
}