float_format/
utils.rs

1use crate::*;
2use bitvec::prelude::*;
3use fraction::{prelude::*, Num};
4
5/// Trait for structure that have an IEEE binary standard form.
6pub trait IeeeBinary {
7    fn ieee_binary32() -> Self;
8    fn ieee_binary64() -> Self;
9}
10
11/// Special interpretation of bit patterns for special values.
12/// This function is called during output.
13pub type Interpret = fn(&Components) -> Option<String>;
14
15/// Function to convert components to a string according to IEEE binary32 and binary64 format.
16fn ieee_interpret(comps: &Components) -> Option<String> {
17    match comps {
18        c if c.sign == Some(false) && c.exp.is_all_zero() && c.mant.is_all_zero() => {
19            Some("0".to_owned())
20        },
21        c if c.sign == Some(true) && c.exp.is_all_zero() && c.mant.is_all_zero() => {
22            Some("-0".to_owned())
23        },
24        c if c.sign == Some(false) && c.exp.is_all_one() && c.mant.is_all_zero() => {
25            Some("inf".to_owned())
26        },
27        c if c.sign == Some(true) && c.exp.is_all_one() && c.mant.is_all_zero() => {
28            Some("-inf".to_owned())
29        },
30        c if c.exp.is_all_one() && !c.mant.is_all_zero() && c.mant.iter().next().map(|b| *b) == Some(true) => {
31            Some("NaN".to_owned())
32        },
33        c if c.exp.is_all_one() && !c.mant.is_all_zero() && c.mant.iter().next().map(|b| *b) == Some(false) => {
34            Some("sNaN".to_owned())
35        },
36        _ => None,
37    }
38}
39
40impl IeeeBinary for Interpret {
41    fn ieee_binary32() -> Self {
42        ieee_interpret
43    }
44
45    fn ieee_binary64() -> Self {
46        ieee_interpret
47    }
48}
49
50pub type BitPattern = BitVec<usize, Msb0>;
51
52pub trait BitPatternExt where Self: Sized {
53    fn from_value<T>(val: T) -> Self
54    where
55        T: BitStore;
56
57    /// Create from the given string.
58    /// The radix is deduced from the first 2 chars.
59    /// '0b' => binary, '0x' => hexadecimal, '0o' => octal, '0d' => decimal.
60    fn from_str(s: &str) -> Result<Self, error::Error>;
61
62    /// Create from the given binary string.
63    /// Any character other than '0' or '1' is ignored.
64    fn from_bin_str(s: &str) -> Self;
65
66    /// Create from the given decimal string.
67    /// Any character other than decimal digits is ignored.
68    fn from_dec_str(s: &str) -> Self;
69    
70    /// Create from the given octal string.
71    /// Any character other than octal digits is ignored.
72    fn from_oct_str(s: &str) -> Self;
73    
74    /// Create from the given hexadecimal string.
75    /// Any character other than hexadecimal digits is ignored.
76    fn from_hex_str(s: &str) -> Self;
77    
78    /// Check if the bit pattern is all one.
79    fn is_all_one(&self) -> bool;
80
81    /// Check if the bit pattern is all zero.
82    fn is_all_zero(&self) -> bool;
83
84    /// Convert the bit pattern to a string representing the binary value.
85    fn to_bin_string(&self) -> String;
86
87    /// Convert the bit pattern to a string representing the decimal value.
88    fn to_oct_string(&self) -> String;
89
90    /// Convert the bit pattern to a string representing the hexadecimal value.
91    fn to_dec_string(&self) -> String;
92
93    /// Convert the bit pattern to a string representing the hexadecimal value.
94    fn to_hex_string(&self) -> String;
95}
96
97impl BitPatternExt for BitPattern {
98    fn from_value<T>(val: T) -> Self
99    where
100        T: BitStore
101    {
102        val.view_bits::<Msb0>().iter().collect()
103    }
104
105    fn from_str(s: &str) -> Result<Self, error::Error> {
106        if s.len() < 3 {
107            return Err(error::Error::InvalidRadixPrefix);
108        }
109
110        match s[0..2].as_ref() {
111            "0b" => Ok(Self::from_bin_str(&s[2..])),
112            "0o" => Ok(Self::from_oct_str(&s[2..])),
113            "0d" => Ok(Self::from_dec_str(&s[2..])),
114            "0x" => Ok(Self::from_hex_str(&s[2..])),
115            _ => Err(error::Error::InvalidRadixPrefix),
116        }
117    }
118    
119    fn from_bin_str(s: &str) -> Self {
120        s
121            .chars()
122            .filter(|c| c.is_digit(2))
123            .map(|c| c == '1')
124            .collect()
125    }
126
127    fn from_dec_str(s: &str) -> Self {
128        let s = s.chars().filter(|c| c.is_digit(10)).collect::<String>();
129
130        let mut int = BigUint::from_str_radix(&s, 10).unwrap();
131        let mut bits = String::new();
132
133        while int > BigUint::from(0u32) {
134            bits.push(if int.clone() % BigUint::from(2u32) == BigUint::from(1u32) { '1' } else { '0' });
135            int /= 2u32;
136        }
137
138        let bits = bits
139            .chars()
140            .rev()
141            .collect::<String>();
142
143        Self::from_bin_str(&bits)
144    }
145
146    fn from_oct_str(s: &str) -> Self {
147        s
148            .chars()
149            .filter(|c| c.is_digit(8))
150            .flat_map(|c| format!("{:3b}", c.to_digit(8).unwrap())
151                .chars()
152                .collect::<Vec<_>>()
153            )
154            .map(|c| c == '1')
155            .collect()
156    }
157    
158    fn from_hex_str(s: &str) -> Self {
159        s
160            .chars()
161            .filter(|c| c.is_digit(16))
162            .flat_map(|c| format!("{:4b}", c.to_digit(16).unwrap())
163                .chars()
164                .collect::<Vec<_>>()
165            )
166            .map(|c| c == '1')
167            .collect()
168    }
169
170    fn is_all_one(&self) -> bool {
171        self.iter().all(|b| *b)
172    }
173
174    fn is_all_zero(&self) -> bool {
175        self.iter().all(|b| !*b)
176    }
177    
178    fn to_bin_string(&self) -> String {
179        self
180            .iter()
181            .map(|b| if *b { '1' } else { '0' })
182            .collect()
183    }
184    
185    fn to_oct_string(&self) -> String {
186        self
187            .as_bitslice()
188            .chunks(3)
189            .map(|c| format!("{:o}", c)
190                .chars()
191                .filter(|c| c.is_digit(8))
192                .collect::<String>()
193            )
194            .collect()
195    }
196
197    fn to_dec_string(&self) -> String {
198        self
199            .iter()
200            .fold(BigUint::from(0u32), |acc, b| acc * 2u32 + if *b { 1u32 } else { 0u32 })
201            .to_string()
202    }
203
204    fn to_hex_string(&self) -> String {
205        self
206            .as_bitslice()
207            .chunks(4)
208            .map(|c| format!("{:x}", c)
209                .chars()
210                .filter(|c| c.is_digit(16))
211                .collect::<String>()
212            )
213            .collect()
214    }
215}