strict_num_extended_macros/
lib.rs1#![cfg_attr(docsrs, feature(doc_cfg))]
5
6use proc_macro::TokenStream;
7use quote::quote;
8use syn::parse_macro_input;
9
10mod arithmetic;
11mod comparison;
12mod config;
13mod constants;
14mod conversion;
15mod doc_generator;
16mod finite_float;
17mod finite_float_trait;
18mod float_conversion;
19mod fromstr_impl;
20mod generator;
21mod option_arithmetic;
22mod result_arithmetic;
23mod type_aliases;
24mod unary_ops;
25
26use arithmetic::{generate_arithmetic_impls, generate_neg_impls};
27use comparison::{generate_comparison_traits, generate_concrete_comparison_traits};
28use config::TypeConfig;
29use constants::generate_constants;
30use conversion::generate_conversion_traits;
31use finite_float::{
32 generate_concrete_impls, generate_concrete_serde_impls, generate_concrete_structs,
33};
34use finite_float_trait::{generate_finite_float_impls, generate_finite_float_trait};
35use float_conversion::{
36 generate_as_f32_primitive_methods, generate_as_f32_type_methods,
37 generate_as_f64_primitive_methods, generate_as_f64_type_methods,
38 generate_try_into_f32_type_methods,
39};
40use fromstr_impl::{
41 generate_fromstr_traits, generate_parse_error_from_impls, generate_parse_error_type,
42};
43use option_arithmetic::generate_option_arithmetic_impls;
44use result_arithmetic::generate_result_arithmetic_impls;
45use type_aliases::generate_type_aliases;
46use unary_ops::{
47 generate_abs_impls, generate_cos_impls, generate_signum_impls, generate_sin_impls,
48 generate_tan_impls,
49};
50
51fn generate_common_definitions() -> proc_macro2::TokenStream {
53 quote! {
54 use core::marker::PhantomData;
55 use core::ops::{Add, Sub, Mul, Div, Neg};
56
57 const F64_MIN_BITS: i64 = f64::MIN.to_bits() as i64;
59 const F64_MAX_BITS: i64 = f64::MAX.to_bits() as i64;
60 const ZERO_BITS: i64 = 0.0f64.to_bits() as i64;
61 const F64_MIN_POSITIVE_BITS: i64 = f64::MIN_POSITIVE.to_bits() as i64;
63 const F64_NEG_MIN_POSITIVE_BITS: i64 = (-f64::MIN_POSITIVE).to_bits() as i64;
64 const ONE_BITS: i64 = 1.0f64.to_bits() as i64;
65 const NEG_ONE_BITS: i64 = (-1.0f64).to_bits() as i64;
66
67 const F32_MIN_BITS: i64 = (f32::MIN as f64).to_bits() as i64;
69 const F32_MAX_BITS: i64 = (f32::MAX as f64).to_bits() as i64;
70 const F32_MIN_POSITIVE_BITS: i64 = (f32::MIN_POSITIVE as f64).to_bits() as i64;
72 const F32_NEG_MIN_POSITIVE_BITS: i64 = ((-f32::MIN_POSITIVE) as f64).to_bits() as i64;
73 }
74}
75
76fn generate_error_type() -> proc_macro2::TokenStream {
78 quote! {
79 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
81 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
82 pub enum FloatError {
83 NaN,
85 PosInf,
87 NegInf,
89 OutOfRange,
91 NoneOperand,
93 }
94
95 impl core::fmt::Display for FloatError {
96 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
97 match self {
98 FloatError::NaN => write!(f, "value is NaN (Not a Number)"),
99 FloatError::PosInf => write!(f, "value is positive infinity"),
100 FloatError::NegInf => write!(f, "value is negative infinity"),
101 FloatError::OutOfRange => write!(f, "value is outside the valid range for this type"),
102 FloatError::NoneOperand => write!(f, "right-hand side operand is None in Option arithmetic"),
103 }
104 }
105 }
106
107 #[cfg(feature = "std")]
108 impl std::error::Error for FloatError {}
109 }
110}
111
112fn generate_constraint_markers(config: &TypeConfig) -> proc_macro2::TokenStream {
114 let markers = config.constraints.iter().map(|constraint| {
115 let name = &constraint.name;
116 quote! {
117 #[doc(hidden)]
118 #[derive(Debug, Clone, Copy)]
119 pub(crate) struct #name;
120 }
121 });
122
123 quote! {
124 #(#markers)*
125 }
126}
127
128#[proc_macro]
130pub fn generate_finite_float_types(input: TokenStream) -> TokenStream {
131 let config = parse_macro_input!(input as TypeConfig);
132
133 let mut all_code = vec![
135 generate_common_definitions(),
136 generate_error_type(),
137 generate_parse_error_type(),
138 generate_parse_error_from_impls(),
139 generate_constraint_markers(&config),
140 generate_concrete_structs(&config),
141 generate_comparison_traits(),
142 ];
143
144 all_code.push(generate_concrete_impls(&config));
146 all_code.push(generate_concrete_serde_impls(&config));
147 all_code.push(generate_concrete_comparison_traits(&config));
148
149 all_code.push(generate_arithmetic_impls(&config));
151
152 all_code.push(generate_option_arithmetic_impls(&config));
154
155 all_code.push(generate_result_arithmetic_impls(&config));
157
158 all_code.push(generate_neg_impls(&config));
160
161 all_code.push(generate_abs_impls(&config));
163 all_code.push(generate_signum_impls(&config));
164
165 all_code.push(generate_sin_impls(&config));
167 all_code.push(generate_cos_impls(&config));
168 all_code.push(generate_tan_impls(&config));
169
170 all_code.push(generate_as_f32_primitive_methods(&config));
177 all_code.push(generate_as_f64_primitive_methods(&config));
178 all_code.push(generate_as_f32_type_methods(&config));
179 all_code.push(generate_as_f64_type_methods(&config));
180 all_code.push(generate_try_into_f32_type_methods(&config));
181
182 all_code.push(generate_conversion_traits(&config));
184
185 all_code.push(generate_fromstr_traits(&config));
187
188 all_code.push(generate_finite_float_trait(&config));
190 all_code.push(generate_finite_float_impls(&config));
191
192 all_code.push(generate_constants(&config));
194
195 all_code.push(generate_type_aliases(&config));
197
198 let expanded = quote! {
200 #(#all_code)*
201 };
202
203 TokenStream::from(expanded)
204}