jtd_infer/
inferred_number.rs1use jtd::Type;
2
3#[derive(Debug)]
4pub struct InferredNumber {
5 min: f64,
6 max: f64,
7 int: bool,
8}
9
10impl InferredNumber {
11 pub fn new() -> Self {
12 Self {
13 min: f64::MAX,
14 max: f64::MIN,
15 int: true,
16 }
17 }
18
19 pub fn infer(&self, n: f64) -> Self {
20 Self {
21 min: self.min.min(n),
22 max: self.max.max(n),
23 int: self.int && n.fract() == 0.0,
24 }
25 }
26
27 pub fn into_type(&self, default: &NumType) -> Type {
28 if self.contained_by(default) {
29 return default.into_type();
30 }
31
32 let types = [
33 NumType::Uint8,
34 NumType::Int8,
35 NumType::Uint16,
36 NumType::Int16,
37 NumType::Uint32,
38 NumType::Int32,
39 ];
40
41 for type_ in &types {
42 if self.contained_by(type_) {
43 return type_.into_type();
44 }
45 }
46
47 return NumType::Float64.into_type();
48 }
49
50 fn contained_by(&self, type_: &NumType) -> bool {
51 if !self.int && !type_.is_float() {
52 return false;
53 }
54
55 let (min, max) = type_.as_range();
56 min <= self.min && max >= self.max
57 }
58}
59
60#[derive(Clone)]
64pub enum NumType {
65 Int8,
67
68 Uint8,
70
71 Int16,
73
74 Uint16,
76
77 Int32,
79
80 Uint32,
82
83 Float32,
85
86 Float64,
88}
89
90impl NumType {
91 fn is_float(&self) -> bool {
92 match self {
93 Self::Float32 | Self::Float64 => true,
94 _ => false,
95 }
96 }
97
98 fn as_range(&self) -> (f64, f64) {
99 match self {
100 Self::Int8 => (i8::MIN as f64, i8::MAX as f64),
101 Self::Uint8 => (u8::MIN as f64, u8::MAX as f64),
102 Self::Int16 => (i16::MIN as f64, i16::MAX as f64),
103 Self::Uint16 => (u16::MIN as f64, u16::MAX as f64),
104 Self::Int32 => (i32::MIN as f64, i32::MAX as f64),
105 Self::Uint32 => (u32::MIN as f64, u32::MAX as f64),
106 Self::Float32 | Self::Float64 => (f64::MIN, f64::MAX),
107 }
108 }
109
110 fn into_type(&self) -> Type {
111 match self {
112 Self::Int8 => Type::Int8,
113 Self::Uint8 => Type::Uint8,
114 Self::Int16 => Type::Int16,
115 Self::Uint16 => Type::Uint16,
116 Self::Int32 => Type::Int32,
117 Self::Uint32 => Type::Uint32,
118 Self::Float32 => Type::Float32,
119 Self::Float64 => Type::Float64,
120 }
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127
128 #[test]
129 fn inferred_number() {
130 let n = InferredNumber::new();
131
132 assert_eq!(Type::Uint8, n.into_type(&NumType::Uint8));
134 assert_eq!(Type::Int8, n.into_type(&NumType::Int8));
135 assert_eq!(Type::Uint16, n.into_type(&NumType::Uint16));
136 assert_eq!(Type::Int16, n.into_type(&NumType::Int16));
137 assert_eq!(Type::Uint32, n.into_type(&NumType::Uint32));
138 assert_eq!(Type::Int32, n.into_type(&NumType::Int32));
139 assert_eq!(Type::Float32, n.into_type(&NumType::Float32));
140 assert_eq!(Type::Float64, n.into_type(&NumType::Float64));
141
142 let n = InferredNumber::new()
144 .infer(u8::MIN as f64)
145 .infer(u8::MAX as f64);
146
147 assert_eq!(Type::Uint8, n.into_type(&NumType::Uint8));
148 assert_eq!(Type::Uint8, n.into_type(&NumType::Int8));
149 assert_eq!(Type::Uint16, n.into_type(&NumType::Uint16));
150 assert_eq!(Type::Int16, n.into_type(&NumType::Int16));
151 assert_eq!(Type::Uint32, n.into_type(&NumType::Uint32));
152 assert_eq!(Type::Int32, n.into_type(&NumType::Int32));
153 assert_eq!(Type::Float32, n.into_type(&NumType::Float32));
154 assert_eq!(Type::Float64, n.into_type(&NumType::Float64));
155
156 let n = InferredNumber::new()
158 .infer(i8::MIN as f64)
159 .infer(i8::MAX as f64);
160
161 assert_eq!(Type::Int8, n.into_type(&NumType::Uint8));
162 assert_eq!(Type::Int8, n.into_type(&NumType::Int8));
163 assert_eq!(Type::Int8, n.into_type(&NumType::Uint16));
164 assert_eq!(Type::Int16, n.into_type(&NumType::Int16));
165 assert_eq!(Type::Int8, n.into_type(&NumType::Uint32));
166 assert_eq!(Type::Int32, n.into_type(&NumType::Int32));
167 assert_eq!(Type::Float32, n.into_type(&NumType::Float32));
168 assert_eq!(Type::Float64, n.into_type(&NumType::Float64));
169
170 let n = InferredNumber::new().infer(0.5);
172 assert_eq!(Type::Float64, n.into_type(&NumType::Uint8));
173 assert_eq!(Type::Float64, n.into_type(&NumType::Int8));
174 assert_eq!(Type::Float64, n.into_type(&NumType::Uint16));
175 assert_eq!(Type::Float64, n.into_type(&NumType::Int16));
176 assert_eq!(Type::Float64, n.into_type(&NumType::Uint32));
177 assert_eq!(Type::Float64, n.into_type(&NumType::Int32));
178 assert_eq!(Type::Float32, n.into_type(&NumType::Float32));
179 assert_eq!(Type::Float64, n.into_type(&NumType::Float64));
180 }
181}