decstr/binary/buf/
arbitrary.rs

1use core::{
2    fmt,
3    ops::Index,
4};
5
6use crate::{
7    binary::{
8        emax,
9        emin,
10        exponent::{
11            add_bias,
12            sub_bias,
13            BinaryExponent,
14        },
15        try_with_at_least_precision,
16        BinaryBuf,
17        BinaryExponentMath,
18    },
19    num::Integer,
20    OverflowError,
21};
22
23use num_bigint::BigInt;
24use num_traits::{
25    Signed,
26    ToPrimitive,
27};
28
29/**
30A buffer that can represent any sized decimal.
31*/
32#[derive(Debug, Clone)]
33pub(crate) struct ArbitrarySizedBinaryBuf(Vec<u8>);
34
35pub(crate) struct ArbitrarySizedBinaryExponent(BigInt);
36
37pub(crate) struct ArbitrarySizedBinaryExponentBytes(Vec<u8>);
38
39impl BinaryBuf for ArbitrarySizedBinaryBuf {
40    type Exponent = ArbitrarySizedBinaryExponent;
41
42    fn try_exponent_from_ascii<I: Iterator<Item = u8>>(
43        is_negative: bool,
44        ascii: I,
45    ) -> Result<ArbitrarySizedBinaryExponent, OverflowError>
46    where
47        Self::Exponent: Sized,
48    {
49        ArbitrarySizedBinaryExponent::try_from_ascii(is_negative, ascii)
50            .ok_or_else(|| OverflowError::exponent_out_of_range(4, "the exponent would overflow"))
51    }
52
53    fn try_with_at_least_storage_width_bytes(bytes: usize) -> Result<Self, OverflowError> {
54        Ok(ArbitrarySizedBinaryBuf(vec![0; bytes]))
55    }
56
57    fn try_with_at_least_precision(
58        integer_digits: usize,
59        integer_exponent: Option<&Self::Exponent>,
60    ) -> Result<Self, OverflowError>
61    where
62        Self: Sized,
63    {
64        try_with_at_least_precision(integer_digits, integer_exponent.map(|e| e.0.clone()))
65    }
66
67    fn bytes_mut(&mut self) -> &mut [u8] {
68        &mut self.0
69    }
70
71    fn bytes(&self) -> &[u8] {
72        &self.0
73    }
74}
75
76impl Integer for ArbitrarySizedBinaryExponent {
77    type Bytes = ArbitrarySizedBinaryExponentBytes;
78
79    fn try_from_ascii<I: Iterator<Item = u8>>(is_negative: bool, ascii: I) -> Option<Self> {
80        Some(ArbitrarySizedBinaryExponent(Integer::try_from_ascii(
81            is_negative,
82            ascii,
83        )?))
84    }
85
86    fn from_le_bytes<I: Iterator<Item = u8>>(bytes: I) -> Self {
87        ArbitrarySizedBinaryExponent(Integer::from_le_bytes(bytes))
88    }
89
90    fn from_i32(exp: i32) -> Self {
91        ArbitrarySizedBinaryExponent(Integer::from_i32(exp))
92    }
93
94    fn to_i32(&self) -> Option<i32> {
95        Integer::to_i32(&self.0)
96    }
97
98    fn is_negative(&self) -> bool {
99        Integer::is_negative(&self.0)
100    }
101
102    fn to_le_bytes(&self) -> Self::Bytes {
103        ArbitrarySizedBinaryExponentBytes(Integer::to_le_bytes(&self.0))
104    }
105
106    fn to_fmt<W: fmt::Write>(&self, out: W) -> fmt::Result {
107        Integer::to_fmt(&self.0, out)
108    }
109}
110
111impl Integer for BigInt {
112    type Bytes = Vec<u8>;
113
114    fn try_from_ascii<I: Iterator<Item = u8>>(is_negative: bool, ascii: I) -> Option<Self>
115    where
116        Self: Sized,
117    {
118        let ascii = ascii.collect::<Vec<_>>();
119        let n = BigInt::parse_bytes(&ascii, 10)?;
120
121        Some(if is_negative { -n } else { n })
122    }
123
124    fn from_le_bytes<I: Iterator<Item = u8>>(bytes: I) -> Self {
125        let buf = bytes.collect::<Vec<_>>();
126
127        BigInt::from_signed_bytes_le(&buf)
128    }
129
130    fn from_i32(n: i32) -> Self {
131        BigInt::from(n)
132    }
133
134    fn to_i32(&self) -> Option<i32> {
135        ToPrimitive::to_i32(self)
136    }
137
138    fn is_negative(&self) -> bool {
139        Signed::is_negative(self)
140    }
141
142    fn to_le_bytes(&self) -> Self::Bytes {
143        self.to_signed_bytes_le()
144    }
145
146    fn to_fmt<W: fmt::Write>(&self, mut out: W) -> fmt::Result {
147        write!(out, "{}", self)
148    }
149}
150
151impl BinaryExponent for ArbitrarySizedBinaryExponent {
152    #[must_use]
153    fn raise(&self, integer_digits: usize) -> Self {
154        ArbitrarySizedBinaryExponent(&self.0 + integer_digits)
155    }
156
157    #[must_use]
158    fn lower(&self, fractional_digits: usize) -> Self {
159        ArbitrarySizedBinaryExponent(&self.0 - fractional_digits)
160    }
161
162    #[must_use]
163    fn bias<D: BinaryBuf>(&self, decimal: &D) -> Self {
164        ArbitrarySizedBinaryExponent(add_bias(decimal, self.0.clone()))
165    }
166
167    #[must_use]
168    fn unbias<D: BinaryBuf>(&self, decimal: &D) -> Self {
169        ArbitrarySizedBinaryExponent(sub_bias(decimal, self.0.clone()))
170    }
171
172    #[must_use]
173    fn emax<D: BinaryBuf>(decimal: &D) -> Self {
174        ArbitrarySizedBinaryExponent(emax(decimal.storage_width_bits()))
175    }
176
177    #[must_use]
178    fn emin<D: BinaryBuf>(decimal: &D) -> Self {
179        ArbitrarySizedBinaryExponent(emin(decimal.storage_width_bits()))
180    }
181}
182
183impl fmt::Display for ArbitrarySizedBinaryExponent {
184    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185        fmt::Display::fmt(&self.0, f)
186    }
187}
188
189impl fmt::Debug for ArbitrarySizedBinaryExponent {
190    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
191        fmt::Debug::fmt(&self.0, f)
192    }
193}
194
195impl Index<usize> for ArbitrarySizedBinaryExponentBytes {
196    type Output = u8;
197
198    fn index(&self, index: usize) -> &Self::Output {
199        // Since the exponent is dynamically sized, it might not actually have as
200        // many bytes as a decimal is expecting. If we don't have one, then return a `0`
201        // byte instead
202        if let Some(b) = self.0.get(index) {
203            b
204        } else {
205            &0
206        }
207    }
208}
209
210impl BinaryExponentMath for BigInt {
211    fn abs(self) -> Self {
212        Signed::abs(&self)
213    }
214
215    fn pow2(e: u32) -> Self {
216        BigInt::from(2).pow(e)
217    }
218
219    fn log2(self) -> usize {
220        // We can approximate log2(i) for a base2 integer i by taking the bit position
221        // of its most significant non-zero bit. The `BigInt` type doesn't use base2
222        // digits though, it uses u32 as digits instead (which are called "limbs"), so we convert
223        // the number into a base2 buffer and then look at the bits in the most significant byte
224
225        let i_base2 = self.to_signed_bytes_le();
226
227        let mut significant_byte_index = i_base2.len() - 1;
228
229        // Find the most significant non-zero byte
230        // We expect `BigInt` not to give us a lot of pointless empty bytes
231        // but it's reasonable to assume it might pad them up to the nearest limb
232        while significant_byte_index > 0 {
233            if i_base2[significant_byte_index] != 0 {
234                break;
235            }
236
237            significant_byte_index -= 1;
238        }
239
240        let significant_bit_index = 8 - i_base2[significant_byte_index].leading_zeros() as usize;
241
242        let log2 = (significant_bit_index + (significant_byte_index * 8)).saturating_sub(1);
243
244        log2
245    }
246}