1use crate::*;
2use alloc::format;
3use core::convert::TryFrom;
4
5mod f32;
6mod f64;
7
8#[derive(Debug, PartialEq)]
14pub enum Real {
15 Binary {
17 mantissa: f64,
18 base: u32,
19 exponent: i32,
20 enc_base: u8,
21 },
22 Infinity,
24 NaN,
26 NegInfinity,
28 Zero,
30}
31
32impl Real {
33 pub fn new(f: f64) -> Self {
35 if f.is_infinite() {
36 if f.is_sign_positive() {
37 Self::Infinity
38 } else {
39 Self::NegInfinity
40 }
41 } else if f.is_nan() {
42 Self::NaN
43 } else if f.abs() == 0.0 {
44 Self::Zero
45 } else {
46 let mut e = 0;
47 let mut f = f;
48 while f.fract() != 0.0 {
49 f *= 10.0_f64;
50 e -= 1;
51 }
52 Real::Binary {
53 mantissa: f,
54 base: 10,
55 exponent: e,
56 enc_base: 10,
57 }
58 .normalize_base10()
59 }
60 }
61
62 pub const fn with_enc_base(self, enc_base: u8) -> Self {
63 match self {
64 Real::Binary {
65 mantissa,
66 base,
67 exponent,
68 ..
69 } => Real::Binary {
70 mantissa,
71 base,
72 exponent,
73 enc_base,
74 },
75 e => e,
76 }
77 }
78
79 fn normalize_base10(self) -> Self {
80 match self {
81 Real::Binary {
82 mantissa,
83 base: 10,
84 exponent,
85 enc_base: _enc_base,
86 } => {
87 let mut m = mantissa;
88 let mut e = exponent;
89 while m.abs() > f64::EPSILON && m.rem_euclid(10.0).abs() < f64::EPSILON {
90 m /= 10.0;
91 e += 1;
92 }
93 Real::Binary {
94 mantissa: m,
95 base: 10,
96 exponent: e,
97 enc_base: _enc_base,
98 }
99 }
100 _ => self,
101 }
102 }
103
104 #[inline]
106 pub const fn binary(mantissa: f64, base: u32, exponent: i32) -> Self {
107 Self::Binary {
108 mantissa,
109 base,
110 exponent,
111 enc_base: 2,
112 }
113 }
114
115 #[inline]
118 pub fn is_infinite(&self) -> bool {
119 matches!(self, Real::Infinity | Real::NegInfinity)
120 }
121
122 #[inline]
124 pub fn is_finite(&self) -> bool {
125 matches!(self, Real::Zero | Real::Binary { .. })
126 }
127
128 pub fn f64(&self) -> f64 {
132 match self {
133 Real::Binary {
134 mantissa,
135 base,
136 exponent,
137 ..
138 } => {
139 let f = mantissa;
140 let exp = (*base as f64).powi(*exponent);
141 f * exp
142 }
143 Real::Zero => 0.0_f64,
144 Real::NaN => f64::NAN,
145 Real::Infinity => f64::INFINITY,
146 Real::NegInfinity => f64::NEG_INFINITY,
147 }
148 }
149
150 pub fn f32(&self) -> f32 {
154 self.f64() as f32
155 }
156}
157
158impl<'a> TryFrom<Any<'a>> for Real {
159 type Error = Error;
160
161 fn try_from(any: Any<'a>) -> Result<Self> {
162 TryFrom::try_from(&any)
163 }
164}
165
166impl<'a, 'b> TryFrom<&'b Any<'a>> for Real {
167 type Error = Error;
168
169 fn try_from(any: &'b Any<'a>) -> Result<Self> {
170 any.tag().assert_eq(Self::TAG)?;
171 any.header.assert_primitive()?;
172 let data = &any.data;
173 if data.is_empty() {
174 return Ok(Real::Zero);
175 }
176 let first = data[0];
178 let rem = &data[1..];
179 if first & 0x80 != 0 {
180 let (n, rem) = match first & 0x03 {
183 4 => {
184 let (b, rem) = rem
185 .split_first()
186 .ok_or_else(|| Error::Incomplete(Needed::new(1)))?;
187 (*b as usize, rem)
188 }
189 b => (b as usize + 1, rem),
190 };
191 if n >= rem.len() {
192 return Err(any.tag().invalid_value("Invalid float value(exponent)"));
193 }
194 let (eo, rem) = rem.split_at(n);
196 let mut e = if eo[0] & 0x80 != 0 { -1 } else { 0 };
198 if eo.len() > 4 {
200 return Err(any.tag().invalid_value("Exponent too large (REAL)"));
201 }
202 for b in eo {
203 e = (e << 8) | (*b as i32);
204 }
205 let b = (first >> 4) & 0x03;
207 let _enc_base = match b {
208 0 => 2,
209 1 => 8,
210 2 => 16,
211 _ => return Err(any.tag().invalid_value("Illegal REAL encoding base")),
212 };
213 let e = match b {
214 0 => e,
216 1 => e * 3,
218 2 => e * 4,
220 _ => return Err(any.tag().invalid_value("Illegal REAL base")),
221 };
222 if rem.len() > 8 {
223 return Err(any.tag().invalid_value("Mantissa too large (REAL)"));
224 }
225 let mut p = 0;
226 for b in rem {
227 p = (p << 8) | (*b as i64);
228 }
229 let p = if first & 0x40 != 0 { -p } else { p };
231 let sf = (first >> 2) & 0x03;
233 let p = match sf {
234 0 => p as f64,
235 sf => {
236 let scale = 2_f64.powi(sf as _);
238 (p as f64) * scale
239 }
240 };
241 Ok(Real::Binary {
242 mantissa: p,
243 base: 2,
244 exponent: e,
245 enc_base: _enc_base,
246 })
247 } else if first & 0x40 != 0 {
248 if any.header.length != Length::Definite(1) {
251 return Err(Error::InvalidLength);
252 }
253 match first {
255 0x40 => Ok(Real::Infinity),
256 0x41 => Ok(Real::NegInfinity),
257 0x42 => Ok(Real::NaN),
258 _ => Err(any.tag().invalid_value("Invalid float special value")),
259 }
260 } else {
261 let s = alloc::str::from_utf8(rem)?;
263 match first & 0x03 {
264 0x1 => {
265 match s.parse::<u32>() {
267 Err(_) => Err(any.tag().invalid_value("Invalid float string encoding")),
268 Ok(v) => Ok(Real::new(v.into())),
269 }
270 }
271 0x2 | 0x3 => {
272 match s.parse::<f64>() {
273 Err(_) => Err(any.tag().invalid_value("Invalid float string encoding")),
274 Ok(v) => Ok(Real::new(v)),
275 }
276 }
277 c => {
278 Err(any.tag().invalid_value(&format!("Invalid NR ({})", c)))
279 }
280 }
281 }
282 }
283}
284
285impl CheckDerConstraints for Real {
286 fn check_constraints(any: &Any) -> Result<()> {
287 any.header.assert_primitive()?;
288 any.header.length.assert_definite()?;
289 Ok(())
291 }
292}
293
294impl DerAutoDerive for Real {}
295
296impl Tagged for Real {
297 const TAG: Tag = Tag::RealType;
298}
299
300#[cfg(feature = "std")]
301impl ToDer for Real {
302 fn to_der_len(&self) -> Result<usize> {
303 match self {
304 Real::Zero => Ok(0),
305 Real::Infinity | Real::NegInfinity | Real::NaN => Ok(1),
306 Real::Binary { .. } => {
307 let mut sink = std::io::sink();
308 let n = self
309 .write_der_content(&mut sink)
310 .map_err(|_| Self::TAG.invalid_value("Serialization of REAL failed"))?;
311 Ok(n)
312 }
313 }
314 }
315
316 fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
317 let header = Header::new(
318 Class::Universal,
319 false,
320 Self::TAG,
321 Length::Definite(self.to_der_len()?),
322 );
323 header.write_der_header(writer)
324 }
325
326 fn write_der_content(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
327 match self {
328 Real::Zero => Ok(0),
329 Real::Infinity => writer.write(&[0x40]).map_err(Into::into),
330 Real::NegInfinity => writer.write(&[0x41]).map_err(Into::into),
331 Real::NaN => writer.write(&[0x42]).map_err(Into::into),
332 Real::Binary {
333 mantissa,
334 base,
335 exponent,
336 enc_base: _enc_base,
337 } => {
338 if *base == 10 {
339 let sign = if *exponent == 0 { "+" } else { "" };
341 let s = format!("\x03{}E{}{}", mantissa, sign, exponent);
342 return writer.write(s.as_bytes()).map_err(Into::into);
343 }
344 if *base != 2 {
345 return Err(Self::TAG.invalid_value("Invalid base for REAL").into());
346 }
347 let mut first: u8 = 0x80;
348 let enc_base = *_enc_base;
350 let (ms, mut m, enc_base, mut e) =
351 drop_floating_point(*mantissa, enc_base, *exponent);
352 assert!(m != 0);
353 if ms < 0 {
354 first |= 0x40
355 };
356 match enc_base {
358 2 => {
359 while m & 0x1 == 0 {
360 m >>= 1;
361 e += 1;
362 }
363 }
364 8 => {
365 while m & 0x7 == 0 {
366 m >>= 3;
367 e += 1;
368 }
369 first |= 0x10;
370 }
371 _ => {
372 while m & 0xf == 0 {
373 m >>= 4;
374 e += 1;
375 }
376 first |= 0x20;
377 }
378 }
379 let mut sf = 0;
382 while m & 0x1 == 0 && sf < 4 {
383 m >>= 1;
384 sf += 1;
385 }
386 first |= sf << 2;
387 let len_e = match e.abs() {
389 0..=0xff => 1,
390 0x100..=0xffff => 2,
391 0x1_0000..=0xff_ffff => 3,
392 _ => 4,
395 };
396 first |= (len_e - 1) & 0x3;
397 let mut n = writer.write(&[first])?;
399 #[allow(clippy::identity_op)]
402 if len_e == 4 {
403 let b = len_e & 0xff;
404 n += writer.write(&[b])?;
405 }
406 let bytes = e.to_be_bytes();
408 n += writer.write(&bytes[(4 - len_e) as usize..])?;
409 let bytes = m.to_be_bytes();
411 let mut idx = 0;
412 for &b in bytes.iter() {
413 if b != 0 {
414 break;
415 }
416 idx += 1;
417 }
418 n += writer.write(&bytes[idx..])?;
419 Ok(n)
420 }
421 }
422 }
423}
424
425impl From<f32> for Real {
426 fn from(f: f32) -> Self {
427 Real::new(f.into())
428 }
429}
430
431impl From<f64> for Real {
432 fn from(f: f64) -> Self {
433 Real::new(f)
434 }
435}
436
437impl From<Real> for f32 {
438 fn from(r: Real) -> Self {
439 r.f32()
440 }
441}
442
443impl From<Real> for f64 {
444 fn from(r: Real) -> Self {
445 r.f64()
446 }
447}
448
449#[cfg(feature = "std")]
450fn drop_floating_point(m: f64, b: u8, e: i32) -> (i8, u64, u8, i32) {
451 let ms = if m.is_sign_positive() { 1 } else { -1 };
452 let es = if e.is_positive() { 1 } else { -1 };
453 let mut m = m.abs();
454 let mut e = e;
455 if b == 8 {
457 m *= 2_f64.powi((e.abs() / 3) * es);
458 e = (e.abs() / 3) * es;
459 } else if b == 16 {
460 m *= 2_f64.powi((e.abs() / 4) * es);
461 e = (e.abs() / 4) * es;
462 }
463 while m.abs() > f64::EPSILON {
465 if m.fract() != 0.0 {
466 m *= b as f64;
467 e -= 1;
468 } else {
469 break;
470 }
471 }
472 (ms, m as u64, b, e)
473}