Skip to main content

rasn/types/
real.rs

1use num_traits::float::FloatCore;
2
3/// Represents a real type in Rust that can be decoded or encoded into any
4/// ASN.1 codec.
5pub trait RealType: Sized + core::fmt::Debug + core::fmt::Display {
6    /// The byte level width of the floating point type.
7    const BYTE_WIDTH: usize;
8
9    /// The infinity (∞) value
10    const INFINITY: Self;
11
12    /// The negative infinity (-∞) value
13    const NEG_INFINITY: Self;
14
15    /// The Not-a-Number value
16    const NAN: Self;
17
18    /// Returns the IEEE 754 encoded bytes of the real type, byte count defined in `usize`
19    fn to_ieee754_bytes(&self) -> (impl AsRef<[u8]>, usize);
20
21    /// Attempts to decode the IEEE 754 encoded bytes into `Self`
22    fn try_from_ieee754_bytes(bytes: &[u8]) -> Result<Self, TryFromRealError>;
23
24    /// Attempts to convert a generic floating point type into `Self`
25    fn try_from_float(value: impl FloatCore) -> Option<Self>;
26
27    /// Attempts to convert `Self` into a generic floating point type
28    fn try_to_float(&self) -> Option<impl FloatCore>;
29
30    /// Returns `true` if the value is positive infinity
31    fn is_infinity(&self) -> bool;
32
33    /// Returns `true` if the value is negative infinity
34    fn is_neg_infinity(&self) -> bool;
35
36    /// Returns `true` if the value is NaN
37    fn is_nan(&self) -> bool;
38}
39
40#[cfg(feature = "f64")]
41impl RealType for f64 {
42    const BYTE_WIDTH: usize = core::mem::size_of::<Self>();
43    const INFINITY: Self = Self::INFINITY;
44    const NEG_INFINITY: Self = Self::NEG_INFINITY;
45    const NAN: Self = Self::NAN;
46
47    #[inline]
48    fn to_ieee754_bytes(&self) -> (impl AsRef<[u8]>, usize) {
49        let bytes = self.to_be_bytes();
50        (bytes, bytes.len())
51    }
52
53    #[inline]
54    fn try_from_ieee754_bytes(bytes: &[u8]) -> Result<Self, TryFromRealError> {
55        let bytes = bytes
56            .try_into()
57            .map_err(|_| TryFromRealError::InvalidEncoding)?;
58
59        Ok(f64::from_be_bytes(bytes))
60    }
61
62    fn try_from_float(value: impl FloatCore) -> Option<Self> {
63        value.to_f64()
64    }
65
66    fn try_to_float(&self) -> Option<impl FloatCore> {
67        Some(*self)
68    }
69
70    #[inline]
71    fn is_infinity(&self) -> bool {
72        *self == Self::INFINITY
73    }
74
75    #[inline]
76    fn is_neg_infinity(&self) -> bool {
77        *self == Self::NEG_INFINITY
78    }
79
80    #[inline]
81    fn is_nan(&self) -> bool {
82        Self::is_nan(*self)
83    }
84}
85
86#[cfg(feature = "f32")]
87impl RealType for f32 {
88    const BYTE_WIDTH: usize = core::mem::size_of::<Self>();
89    const INFINITY: Self = Self::INFINITY;
90    const NEG_INFINITY: Self = Self::NEG_INFINITY;
91    const NAN: Self = Self::NAN;
92
93    #[inline]
94    fn to_ieee754_bytes(&self) -> (impl AsRef<[u8]>, usize) {
95        let bytes = self.to_be_bytes();
96        (bytes, bytes.len())
97    }
98
99    #[inline]
100    fn try_from_ieee754_bytes(bytes: &[u8]) -> Result<Self, TryFromRealError> {
101        let bytes = bytes
102            .try_into()
103            .map_err(|_| TryFromRealError::InvalidEncoding)?;
104
105        Ok(f32::from_be_bytes(bytes))
106    }
107
108    fn try_from_float(value: impl FloatCore) -> Option<Self> {
109        value.to_f32()
110    }
111
112    fn try_to_float(&self) -> Option<impl FloatCore> {
113        Some(*self)
114    }
115
116    #[inline]
117    fn is_infinity(&self) -> bool {
118        *self == Self::INFINITY
119    }
120
121    #[inline]
122    fn is_neg_infinity(&self) -> bool {
123        *self == Self::NEG_INFINITY
124    }
125
126    #[inline]
127    fn is_nan(&self) -> bool {
128        Self::is_nan(*self)
129    }
130}
131
132#[derive(Debug, Clone, PartialEq, Eq)]
133pub enum TryFromRealError {
134    InvalidEncoding,
135}