asn1_rs/asn1_types/
real.rs

1use crate::*;
2use alloc::format;
3use core::convert::TryFrom;
4
5mod f32;
6mod f64;
7
8/// ASN.1 `REAL` type
9///
10/// # Limitations
11///
12/// When encoding binary values, only base 2 is supported
13#[derive(Debug, PartialEq)]
14pub enum Real {
15    /// Non-special values
16    Binary {
17        mantissa: f64,
18        base: u32,
19        exponent: i32,
20        enc_base: u8,
21    },
22    /// Infinity (∞).
23    Infinity,
24    /// Not-a-number (NaN)
25    NaN,
26    /// Negative infinity (−∞).
27    NegInfinity,
28    /// Zero
29    Zero,
30}
31
32impl Real {
33    /// Create a new `REAL` from the `f64` value.
34    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    /// Create a new binary `REAL`
105    #[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    /// Returns `true` if this value is positive infinity or negative infinity, and
116    /// `false` otherwise.
117    #[inline]
118    pub fn is_infinite(&self) -> bool {
119        matches!(self, Real::Infinity | Real::NegInfinity)
120    }
121
122    /// Returns `true` if this number is not infinite.
123    #[inline]
124    pub fn is_finite(&self) -> bool {
125        matches!(self, Real::Zero | Real::Binary { .. })
126    }
127
128    /// Returns the 'f64' value of this `REAL`.
129    ///
130    /// Returned value is a float, and may be infinite.
131    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    /// Returns the 'f32' value of this `REAL`.
151    ///
152    /// This functions casts the result of [`Real::f64`] to a `f32`, and loses precision.
153    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        // code inspired from pyasn1
177        let first = data[0];
178        let rem = &data[1..];
179        if first & 0x80 != 0 {
180            // binary encoding (X.690 section 8.5.6)
181            // format of exponent
182            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            // n cannot be 0 (see the +1 above)
195            let (eo, rem) = rem.split_at(n);
196            // so 'eo' cannot be empty
197            let mut e = if eo[0] & 0x80 != 0 { -1 } else { 0 };
198            // safety check: 'eo' length must be <= container type for 'e'
199            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            // base bits
206            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                // base 2
215                0 => e,
216                // base 8
217                1 => e * 3,
218                // base 16
219                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            // sign bit
230            let p = if first & 0x40 != 0 { -p } else { p };
231            // scale bits
232            let sf = (first >> 2) & 0x03;
233            let p = match sf {
234                0 => p as f64,
235                sf => {
236                    // 2^sf: cannot overflow, sf is between 0 and 3
237                    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            // special real value (X.690 section 8.5.8)
249            // there shall be only one contents octet,
250            if any.header.length != Length::Definite(1) {
251                return Err(Error::InvalidLength);
252            }
253            // with values as follows
254            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            // decimal encoding (X.690 section 8.5.7)
262            let s = alloc::str::from_utf8(rem)?;
263            match first & 0x03 {
264                0x1 => {
265                    // NR1
266                    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 /* NR2 */ | 0x3 /* NR3 */=> {
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        // XXX more checks
290        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                    // using character form
340                    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                // choose encoding base
349                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                // exponent & mantissa normalization
357                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                    _ /* 16 */ => {
372                        while m & 0xf == 0 {
373                            m >>= 4;
374                            e += 1;
375                        }
376                        first |= 0x20;
377                    }
378                }
379                // scale factor
380                // XXX in DER, sf is always 0 (11.3.1)
381                let mut sf = 0;
382                while m & 0x1 == 0 && sf < 4 {
383                    m >>= 1;
384                    sf += 1;
385                }
386                first |= sf << 2;
387                // exponent length and bytes
388                let len_e = match e.abs() {
389                    0..=0xff => 1,
390                    0x100..=0xffff => 2,
391                    0x1_0000..=0xff_ffff => 3,
392                    // e is an `i32` so it can't be longer than 4 bytes
393                    // use 4, so `first` is ORed with 3
394                    _ => 4,
395                };
396                first |= (len_e - 1) & 0x3;
397                // write first byte
398                let mut n = writer.write(&[first])?;
399                // write exponent
400                // special case: number of bytes from exponent is > 3 and cannot fit in 2 bits
401                #[allow(clippy::identity_op)]
402                if len_e == 4 {
403                    let b = len_e & 0xff;
404                    n += writer.write(&[b])?;
405                }
406                // we only need to write e.len() bytes
407                let bytes = e.to_be_bytes();
408                n += writer.write(&bytes[(4 - len_e) as usize..])?;
409                // write mantissa
410                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    //
456    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    //
464    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}