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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//! `FiniteFloat` trait generation module
//!
//! Generates the `FiniteFloat` trait and its implementations for all generated types.
use proc_macro2::TokenStream;
use quote::quote;
use crate::config::TypeConfig;
use crate::generator::{for_all_constraint_float_types, make_type_alias};
/// Generates `IntoF64` trait and its implementations for f32 and f64
fn generate_into_f64_trait() -> TokenStream {
quote! {
/// Type marker trait: types that can be converted to f64
pub trait IntoF64 {
/// Converts the value to f64
fn into_f64(self) -> f64;
}
impl IntoF64 for f32 {
#[inline]
fn into_f64(self) -> f64 {
self as f64
}
}
impl IntoF64 for f64 {
#[inline]
fn into_f64(self) -> f64 {
self
}
}
}
}
/// Generates the `FiniteFloat` trait definition
///
/// This trait provides a unified interface for all finite floating-point types,
/// allowing polymorphic usage through `Box<dyn FiniteFloat>`.
pub fn generate_finite_float_trait(_config: &TypeConfig) -> TokenStream {
let into_f64_trait = generate_into_f64_trait();
quote! {
#into_f64_trait
/// Common trait for all finite floating-point types
///
/// This trait provides a unified interface for creating and working with
/// finite floating-point numbers, supporting polymorphic usage.
///
/// # Example
///
/// ```
/// use strict_num_extended::{FiniteFloat, FinF32, FinF64, PositiveF32};
///
/// // Create a heterogeneous collection
/// let mut floats: Vec<Box<dyn FiniteFloat>> = Vec::new();
/// floats.push(Box::new(FinF32::new(1.0f32).unwrap()));
/// floats.push(Box::new(FinF64::new(2.0).unwrap()));
/// floats.push(Box::new(PositiveF32::new(0.5f32).unwrap()));
///
/// // All values can be converted to f64
/// assert_eq!(floats[0].as_f64(), 1.0);
/// ```
pub trait FiniteFloat {
/// Creates a new instance from a value that can be converted to f64
///
/// This method accepts both f32 and f64 values through the `IntoF64` trait.
///
/// # Type Parameters
///
/// * `T` - A type implementing `IntoF64` (f32 or f64)
///
/// # Examples
///
/// ```
/// use strict_num_extended::{FiniteFloat, FinF32, FinF64};
///
/// // Create from f32
/// let f32_val: FinF32 = FiniteFloat::new(3.14f32).unwrap();
///
/// // Create from f64
/// let f64_val: FinF64 = FiniteFloat::new(2.71).unwrap();
/// ```
fn new<T: IntoF64>(value: T) -> Result<Self, FloatError>
where
Self: Sized;
/// Converts the value to f64
///
/// # Examples
///
/// ```
/// use strict_num_extended::{FiniteFloat, FinF32};
///
/// let val = FinF32::new(2.5f32).unwrap();
/// assert_eq!(val.as_f64(), 2.5);
/// ```
fn as_f64(&self) -> f64;
}
}
}
/// Generates `FiniteFloat` trait implementations for all constraint types
///
/// This function iterates through all generated types (`FinF32`, `FinF64`, `PositiveF32`, etc.)
/// and generates the corresponding `FiniteFloat` trait implementations.
pub fn generate_finite_float_impls(config: &TypeConfig) -> TokenStream {
let impls = for_all_constraint_float_types(config, |type_name, float_type, _| {
let struct_name = make_type_alias(type_name, float_type);
quote! {
impl FiniteFloat for #struct_name {
fn new<T: IntoF64>(value: T) -> Result<Self, FloatError> {
let f64_val = value.into_f64();
#struct_name::new(f64_val as #float_type)
}
fn as_f64(&self) -> f64 {
self.get() as f64
}
}
}
});
quote! {
#(#impls)*
}
}