xsd_types/lexical/
double.rs1use super::{lexical_form, Decimal, Float, FloatBuf, Integer, Overflow};
2use std::borrow::{Borrow, ToOwned};
3use std::fmt;
4use std::hash::Hash;
5
6lexical_form! {
7 ty: Double,
11
12 buffer: DoubleBuf,
16
17 new,
22
23 new_unchecked,
29
30 value: crate::Double,
31 error: InvalidDouble,
32 as_ref: as_double,
33 parent_forms: {}
34}
35
36pub const NAN: &Double = unsafe { Double::new_unchecked_from_slice(b"NaN") };
37pub const POSITIVE_INFINITY: &Double = unsafe { Double::new_unchecked_from_slice(b"INF") };
38pub const NEGATIVE_INFINITY: &Double = unsafe { Double::new_unchecked_from_slice(b"-INF") };
39
40impl Double {
41 pub fn is_infinite(&self) -> bool {
42 matches!(&self.0, b"INF" | b"-INF")
43 }
44
45 pub fn is_finite(&self) -> bool {
46 !matches!(&self.0, b"INF" | b"-INF" | b"NaN")
47 }
48
49 pub fn is_nan(&self) -> bool {
50 &self.0 == b"NaN"
51 }
52
53 fn exponent_separator_index(&self) -> Option<usize> {
54 for (i, c) in self.0.iter().enumerate() {
55 if matches!(c, b'e' | b'E') {
56 return Some(i);
57 }
58 }
59
60 None
61 }
62
63 pub fn mantissa(&self) -> Option<&Decimal> {
64 if self.is_finite() {
65 Some(match self.exponent_separator_index() {
66 Some(e) => unsafe { Decimal::new_unchecked(&self[..e]) },
67 None => unsafe { Decimal::new_unchecked(self) },
68 })
69 } else {
70 None
71 }
72 }
73
74 pub fn exponent(&self) -> Option<&Integer> {
75 if self.is_finite() {
76 self.exponent_separator_index()
77 .map(|e| unsafe { Integer::new_unchecked(&self[(e + 1)..]) })
78 } else {
79 None
80 }
81 }
82
83 pub fn value(&self) -> crate::Double {
84 self.into()
85 }
86}
87
88impl PartialEq for Double {
89 fn eq(&self, other: &Self) -> bool {
90 self.as_bytes() == other.as_bytes()
91 }
92}
93
94impl Eq for Double {}
95
96impl Hash for Double {
97 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
98 self.as_bytes().hash(state)
99 }
100}
101
102macro_rules! integer_conversion {
103 { $($ty:ty),* } => {
104 $(
105 impl From<$ty> for DoubleBuf {
106 fn from(i: $ty) -> Self {
107 unsafe { DoubleBuf::new_unchecked(i.to_string()) }
108 }
109 }
110
111 impl<'a> TryFrom<&'a Double> for $ty {
112 type Error = Overflow;
113
114 fn try_from(i: &'a Double) -> Result<Self, Overflow> {
115 i.as_str().parse().map_err(|_| Overflow)
116 }
117 }
118
119 impl TryFrom<DoubleBuf> for $ty {
120 type Error = Overflow;
121
122 fn try_from(i: DoubleBuf) -> Result<Self, Overflow> {
123 i.as_str().parse().map_err(|_| Overflow)
124 }
125 }
126 )*
127 };
128}
129
130integer_conversion! {
131 u8,
132 i8,
133 u16,
134 i16,
135 u32,
136 i32,
137 u64,
138 i64,
139 usize,
140 isize
141}
142
143const DTOA_CONFIG: pretty_dtoa::FmtFloatConfig = pretty_dtoa::FmtFloatConfig::default();
144
145impl From<f32> for DoubleBuf {
146 fn from(i: f32) -> Self {
147 if i.is_finite() {
148 unsafe { DoubleBuf::new_unchecked(pretty_dtoa::ftoa(i, DTOA_CONFIG)) }
149 } else if i.is_nan() {
150 DoubleBuf::nan()
151 } else if i.is_sign_positive() {
152 DoubleBuf::positive_infinity()
153 } else {
154 DoubleBuf::negative_infinity()
155 }
156 }
157}
158
159impl<'a> From<&'a Double> for f64 {
160 fn from(i: &'a Double) -> Self {
161 i.as_str().parse().unwrap()
162 }
163}
164
165impl From<DoubleBuf> for f64 {
166 fn from(i: DoubleBuf) -> Self {
167 i.as_str().parse().unwrap()
168 }
169}
170
171impl<'a> From<&'a Float> for f64 {
172 fn from(i: &'a Float) -> Self {
173 i.as_str().parse().unwrap()
174 }
175}
176
177impl From<FloatBuf> for f64 {
178 fn from(i: FloatBuf) -> Self {
179 i.as_str().parse().unwrap()
180 }
181}
182
183impl From<f64> for DoubleBuf {
184 fn from(i: f64) -> Self {
185 if i.is_finite() {
186 unsafe { DoubleBuf::new_unchecked(pretty_dtoa::dtoa(i, DTOA_CONFIG)) }
187 } else if i.is_nan() {
188 DoubleBuf::nan()
189 } else if i.is_sign_positive() {
190 DoubleBuf::positive_infinity()
191 } else {
192 DoubleBuf::negative_infinity()
193 }
194 }
195}
196
197impl<'a> From<&'a Decimal> for &'a Double {
198 #[inline(always)]
199 fn from(d: &'a Decimal) -> Self {
200 unsafe { Double::new_unchecked(d) }
201 }
202}
203
204impl DoubleBuf {
205 #[inline(always)]
206 pub fn nan() -> Self {
207 NAN.to_owned()
208 }
209
210 #[inline(always)]
211 pub fn positive_infinity() -> Self {
212 POSITIVE_INFINITY.to_owned()
213 }
214
215 #[inline(always)]
216 pub fn negative_infinity() -> Self {
217 NEGATIVE_INFINITY.to_owned()
218 }
219}
220
221fn check_bytes(s: &[u8]) -> bool {
222 s == b"INF" || s == b"-INF" || s == b"NaN" || check_normal(s.iter().cloned())
223}
224
225fn check_normal<C: Iterator<Item = u8>>(mut chars: C) -> bool {
226 enum State {
227 Initial,
228 NonEmptyInteger,
229 Integer,
230 NonEmptyDecimal,
231 Decimal,
232 ExponentSign,
233 NonEmptyExponent,
234 Exponent,
235 }
236
237 let mut state = State::Initial;
238
239 loop {
240 state = match state {
241 State::Initial => match chars.next() {
242 Some(b'+') => State::NonEmptyInteger,
243 Some(b'-') => State::NonEmptyInteger,
244 Some(b'.') => State::NonEmptyDecimal,
245 Some(b'0'..=b'9') => State::Integer,
246 _ => break false,
247 },
248 State::NonEmptyInteger => match chars.next() {
249 Some(b'0'..=b'9') => State::Integer,
250 Some(b'.') => State::Decimal,
251 _ => break false,
252 },
253 State::Integer => match chars.next() {
254 Some(b'0'..=b'9') => State::Integer,
255 Some(b'.') => State::Decimal,
256 Some(b'e' | b'E') => State::ExponentSign,
257 Some(_) => break false,
258 None => break true,
259 },
260 State::NonEmptyDecimal => match chars.next() {
261 Some(b'0'..=b'9') => State::Decimal,
262 _ => break false,
263 },
264 State::Decimal => match chars.next() {
265 Some(b'0'..=b'9') => State::Decimal,
266 Some(b'e' | b'E') => State::ExponentSign,
267 Some(_) => break false,
268 None => break true,
269 },
270 State::ExponentSign => match chars.next() {
271 Some(b'+' | b'-') => State::NonEmptyExponent,
272 Some(b'0'..=b'9') => State::Exponent,
273 _ => break false,
274 },
275 State::NonEmptyExponent => match chars.next() {
276 Some(b'0'..=b'9') => State::Exponent,
277 _ => break false,
278 },
279 State::Exponent => match chars.next() {
280 Some(b'0'..=b'9') => State::Exponent,
281 Some(_) => break false,
282 None => break true,
283 },
284 }
285 }
286}
287
288#[cfg(test)]
289mod tests {
290 use super::*;
291
292 #[test]
293 fn parse_01() {
294 Double::new("0").unwrap();
295 }
296
297 #[test]
298 #[should_panic]
299 fn parse_02() {
300 Double::new("+").unwrap();
301 }
302
303 #[test]
304 #[should_panic]
305 fn parse_03() {
306 Double::new("-").unwrap();
307 }
308
309 #[test]
310 #[should_panic]
311 fn parse_04() {
312 Double::new("012+").unwrap();
313 }
314
315 #[test]
316 fn parse_05() {
317 Double::new("+42").unwrap();
318 }
319
320 #[test]
321 fn parse_06() {
322 Double::new("-42").unwrap();
323 }
324
325 #[test]
326 #[should_panic]
327 fn parse_07() {
328 Double::new(".").unwrap();
329 }
330
331 #[test]
332 fn parse_08() {
333 Double::new(".0").unwrap();
334 }
335
336 #[test]
337 fn parse_09() {
338 Double::new("0.").unwrap();
339 }
340
341 #[test]
342 fn parse_10() {
343 Double::new("42.0").unwrap();
344 }
345
346 #[test]
347 fn parse_11() {
348 Double::new("INF").unwrap();
349 }
350
351 #[test]
352 fn parse_12() {
353 Double::new("-INF").unwrap();
354 }
355
356 #[test]
357 fn parse_13() {
358 Double::new("NaN").unwrap();
359 }
360
361 #[test]
362 fn parse_14() {
363 Double::new(".0e1").unwrap();
364 }
365
366 #[test]
367 fn parse_15() {
368 Double::new("0.e1").unwrap();
369 }
370
371 #[test]
372 fn parse_16() {
373 Double::new("42E10").unwrap();
374 }
375
376 #[test]
377 fn parse_17() {
378 Double::new("-42E+10").unwrap();
379 }
380
381 #[test]
382 fn parse_18() {
383 Double::new("-42E-10").unwrap();
384 }
385
386 #[test]
387 #[should_panic]
388 fn parse_19() {
389 Double::new("+42E-10e").unwrap();
390 }
391
392 #[test]
393 fn parse_20() {
394 Double::new("+42E-10").unwrap();
395 }
396
397 #[test]
398 fn parse_21() {
399 let d = Double::new("+01234E-56789").unwrap();
400 assert_eq!(d.mantissa(), Some(Decimal::new("+01234").unwrap()));
401 assert_eq!(d.exponent(), Some(Integer::new("-56789").unwrap()));
402 }
403
404 #[test]
405 fn parse_22() {
406 let a = DoubleBuf::new("+01234E-56789".to_string()).unwrap();
407 let b = Double::new("+01234E-56789").unwrap();
408 assert_eq!(a, b)
409 }
410
411 #[test]
412 fn format_01() {
413 assert_eq!(DoubleBuf::from(1.0e10f64).to_string(), "1.0e10")
414 }
415}