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