Skip to main content

a/math/numbers/
number.rs

1use super::ByteOrder;
2use core::fmt;
3
4/// An integer of any size, stored as its sign and the bytes of its absolute value.
5///
6/// `value` holds the absolute value (the magnitude) of the integer as bytes, in the order
7/// `byte_order` names: the most significant byte first for [`ByteOrder::BigEndian`], the
8/// least significant first for [`ByteOrder::LittleEndian`]. `negative` holds the sign. This
9/// is the sign-and-magnitude form most big-integer libraries use: `-2` is `[2]` with
10/// `negative` set, not the two's-complement byte `[0xFE]`.
11///
12/// The constructors keep the shortest form: they drop the zero bytes above the most
13/// significant non-zero byte and keep one byte for zero, so `1` and `-1` are `[1]`, and `0` is
14/// `[0]`, in either order. An empty `value` is zero as well; the constructors keep an empty
15/// vector empty. Zero is never negative: there is one zero, not a positive and a negative one.
16///
17/// The fields are public, so a `Number` can also be built directly; it is then stored exactly
18/// as given, zero bytes and the sign of zero included.
19///
20/// # Examples
21///
22/// ```
23/// use a::math::numbers::{ByteOrder, Number};
24///
25/// let big = Number::new_from_i32(-0x0001_0203, ByteOrder::BigEndian);
26/// assert_eq!(big.value, [0x01, 0x02, 0x03]);
27/// assert!(big.is_negative());
28///
29/// let little = Number::new_from_u32(0x0001_0203, ByteOrder::LittleEndian);
30/// assert_eq!(little.value, [0x03, 0x02, 0x01]);
31/// assert!(!little.is_negative());
32/// ```
33pub struct Number {
34    /// The bytes of the absolute value of the number, in the order of `byte_order`.
35    pub value: Vec<u8>,
36    /// Whether the number is below zero; `false` for zero.
37    pub negative: bool,
38    /// The order of the bytes in `value`.
39    pub byte_order: ByteOrder,
40}
41
42impl Number {
43    /// Creates a non-negative number from its bytes in `byte_order`, dropping the zero bytes
44    /// above the most significant non-zero byte: the leading zeros in big-endian order, the
45    /// trailing zeros in little-endian order.
46    ///
47    /// Zero bytes below the most significant non-zero byte are part of the number and stay.
48    /// A number whose bytes are all zero keeps one of them, `[0]`; an empty vector stays
49    /// empty.
50    ///
51    /// Takes `O(n)` time for `n` bytes and reuses the allocation of `value`. For a negative
52    /// number, see [`new_signed`](Self::new_signed).
53    ///
54    /// # Examples
55    ///
56    /// ```
57    /// use a::math::numbers::{ByteOrder, Number};
58    ///
59    /// let n = Number::new(vec![0, 0, 1, 0, 2], ByteOrder::BigEndian);
60    /// assert_eq!(n.value, [1, 0, 2]);
61    ///
62    /// let n = Number::new(vec![2, 0, 1, 0, 0], ByteOrder::LittleEndian);
63    /// assert_eq!(n.value, [2, 0, 1]);
64    ///
65    /// let zero = Number::new(vec![0, 0, 0], ByteOrder::BigEndian);
66    /// assert_eq!(zero.value, [0]);
67    /// ```
68    pub fn new(mut value: Vec<u8>, byte_order: ByteOrder) -> Self {
69        match byte_order {
70            // The most significant byte comes first: drop everything before the first
71            // non-zero byte, or all but the last byte when every byte is zero.
72            ByteOrder::BigEndian => {
73                let start = value
74                    .iter()
75                    .position(|&b| b != 0)
76                    .unwrap_or(value.len().saturating_sub(1));
77                value.drain(..start);
78            }
79            // The most significant byte comes last: cut everything after the last non-zero
80            // byte, or all but the first byte when every byte is zero.
81            ByteOrder::LittleEndian => {
82                let end = value.iter().rposition(|&b| b != 0).map_or(1, |i| i + 1);
83                value.truncate(end);
84            }
85        }
86        Self {
87            value,
88            negative: false,
89            byte_order,
90        }
91    }
92
93    /// Creates a number from the bytes of its absolute value in `byte_order` and its sign,
94    /// dropping the high zero bytes as [`new`](Self::new) does.
95    ///
96    /// The number is negative when `negative` is set and the bytes are not all zero: zero is
97    /// never negative.
98    ///
99    /// # Examples
100    ///
101    /// ```
102    /// use a::math::numbers::{ByteOrder, Number};
103    ///
104    /// let n = Number::new_signed(vec![0, 1, 0], true, ByteOrder::BigEndian);
105    /// assert_eq!(n.value, [1, 0]);
106    /// assert!(n.is_negative());
107    ///
108    /// let zero = Number::new_signed(vec![0, 0], true, ByteOrder::BigEndian);
109    /// assert_eq!(zero.value, [0]);
110    /// assert!(!zero.is_negative());
111    /// ```
112    pub fn new_signed(value: Vec<u8>, negative: bool, byte_order: ByteOrder) -> Self {
113        let number = Self::new(value, byte_order);
114        // Once trimmed, zero is `[0]` or `[]` in either order: it keeps the sign of `new`.
115        let negative = negative && !matches!(number.value.as_slice(), [] | [0]);
116        Self { negative, ..number }
117    }
118
119    /// Creates a number from a `u8`, its only byte. Zero is kept as `[0]`.
120    pub fn new_from_u8(value: u8, byte_order: ByteOrder) -> Self {
121        Self::new(vec![value], byte_order)
122    }
123
124    /// Creates a number from the bytes of a `u16` in `byte_order`, without the high zero
125    /// bytes (see [`new`](Self::new)).
126    pub fn new_from_u16(value: u16, byte_order: ByteOrder) -> Self {
127        let bytes = match byte_order {
128            ByteOrder::BigEndian => value.to_be_bytes().to_vec(),
129            ByteOrder::LittleEndian => value.to_le_bytes().to_vec(),
130        };
131        Self::new(bytes, byte_order)
132    }
133
134    /// Creates a number from the bytes of a `u32` in `byte_order`, without the high zero
135    /// bytes (see [`new`](Self::new)).
136    pub fn new_from_u32(value: u32, byte_order: ByteOrder) -> Self {
137        let bytes = match byte_order {
138            ByteOrder::BigEndian => value.to_be_bytes().to_vec(),
139            ByteOrder::LittleEndian => value.to_le_bytes().to_vec(),
140        };
141        Self::new(bytes, byte_order)
142    }
143
144    /// Creates a number from the bytes of a `u64` in `byte_order`, without the high zero
145    /// bytes (see [`new`](Self::new)).
146    ///
147    /// # Examples
148    ///
149    /// ```
150    /// use a::math::numbers::{ByteOrder, Number};
151    ///
152    /// let n = Number::new_from_u64(0x0A0B_0C0D, ByteOrder::BigEndian);
153    /// assert_eq!(n.value, [0x0A, 0x0B, 0x0C, 0x0D]);
154    ///
155    /// let n = Number::new_from_u64(0x0A0B_0C0D, ByteOrder::LittleEndian);
156    /// assert_eq!(n.value, [0x0D, 0x0C, 0x0B, 0x0A]);
157    ///
158    /// let zero = Number::new_from_u64(0, ByteOrder::LittleEndian);
159    /// assert_eq!(zero.value, [0]);
160    /// ```
161    pub fn new_from_u64(value: u64, byte_order: ByteOrder) -> Self {
162        let bytes = match byte_order {
163            ByteOrder::BigEndian => value.to_be_bytes().to_vec(),
164            ByteOrder::LittleEndian => value.to_le_bytes().to_vec(),
165        };
166        Self::new(bytes, byte_order)
167    }
168
169    /// Creates a number from the bytes of a `u128` in `byte_order`, without the high zero
170    /// bytes (see [`new`](Self::new)).
171    pub fn new_from_u128(value: u128, byte_order: ByteOrder) -> Self {
172        let bytes = match byte_order {
173            ByteOrder::BigEndian => value.to_be_bytes().to_vec(),
174            ByteOrder::LittleEndian => value.to_le_bytes().to_vec(),
175        };
176        Self::new(bytes, byte_order)
177    }
178
179    /// Creates a number from the bytes of a `usize` in `byte_order`, without the high zero
180    /// bytes (see [`new`](Self::new)).
181    ///
182    /// `usize` is as wide as a pointer, but as the high zero bytes are dropped, a value has
183    /// the same bytes on every target.
184    pub fn new_from_usize(value: usize, byte_order: ByteOrder) -> Self {
185        let bytes = match byte_order {
186            ByteOrder::BigEndian => value.to_be_bytes().to_vec(),
187            ByteOrder::LittleEndian => value.to_le_bytes().to_vec(),
188        };
189        Self::new(bytes, byte_order)
190    }
191
192    /// Creates a non-negative number from bytes given as `i8`s in `byte_order`, without the
193    /// high zero bytes (see [`new`](Self::new)).
194    ///
195    /// The `i8`s are only how the bytes are given, not signed digits: each one is the byte
196    /// with the same bits (`-1` is `0xFF`, `-128` is `0x80`), and the number is never
197    /// negative.
198    ///
199    /// # Examples
200    ///
201    /// ```
202    /// use a::math::numbers::{ByteOrder, Number};
203    ///
204    /// let n = Number::new_from_i8_vec(vec![0, -1, 1], ByteOrder::BigEndian);
205    /// assert_eq!(n.value, [0xFF, 0x01]);
206    /// assert!(!n.is_negative());
207    /// ```
208    pub fn new_from_i8_vec(value: Vec<i8>, byte_order: ByteOrder) -> Self {
209        Self::new(value.iter().map(|&x| x as u8).collect(), byte_order)
210    }
211
212    /// Creates a number from an `i8`: its sign, and its absolute value as the only byte.
213    /// `i8::MIN` becomes `[0x80]` with `negative` set. Zero is kept as `[0]`.
214    pub fn new_from_i8(value: i8, byte_order: ByteOrder) -> Self {
215        // `unsigned_abs` is exact for every value, `MIN` included, whose absolute value does
216        // not fit in the signed type; the same holds for the wider types below.
217        Self {
218            negative: value < 0,
219            ..Self::new_from_u8(value.unsigned_abs(), byte_order)
220        }
221    }
222
223    /// Creates a number from an `i16`: its sign, and the bytes of its absolute value in
224    /// `byte_order` without the high zero bytes (see [`new`](Self::new)).
225    ///
226    /// # Examples
227    ///
228    /// ```
229    /// use a::math::numbers::{ByteOrder, Number};
230    ///
231    /// let n = Number::new_from_i16(-2, ByteOrder::BigEndian);
232    /// assert_eq!(n.value, [0x02]);
233    /// assert!(n.is_negative());
234    ///
235    /// let n = Number::new_from_i16(i16::MIN, ByteOrder::BigEndian);
236    /// assert_eq!(n.value, [0x80, 0x00]);
237    /// assert!(n.is_negative());
238    /// ```
239    pub fn new_from_i16(value: i16, byte_order: ByteOrder) -> Self {
240        Self {
241            negative: value < 0,
242            ..Self::new_from_u16(value.unsigned_abs(), byte_order)
243        }
244    }
245
246    /// Creates a number from an `i32`: its sign, and the bytes of its absolute value in
247    /// `byte_order` without the high zero bytes (see [`new`](Self::new)).
248    pub fn new_from_i32(value: i32, byte_order: ByteOrder) -> Self {
249        Self {
250            negative: value < 0,
251            ..Self::new_from_u32(value.unsigned_abs(), byte_order)
252        }
253    }
254
255    /// Creates a number from an `i64`: its sign, and the bytes of its absolute value in
256    /// `byte_order` without the high zero bytes (see [`new`](Self::new)).
257    pub fn new_from_i64(value: i64, byte_order: ByteOrder) -> Self {
258        Self {
259            negative: value < 0,
260            ..Self::new_from_u64(value.unsigned_abs(), byte_order)
261        }
262    }
263
264    /// Creates a number from an `i128`: its sign, and the bytes of its absolute value in
265    /// `byte_order` without the high zero bytes (see [`new`](Self::new)).
266    pub fn new_from_i128(value: i128, byte_order: ByteOrder) -> Self {
267        Self {
268            negative: value < 0,
269            ..Self::new_from_u128(value.unsigned_abs(), byte_order)
270        }
271    }
272
273    /// Creates a number from an `isize`: its sign, and the bytes of its absolute value in
274    /// `byte_order` without the high zero bytes (see [`new`](Self::new)).
275    ///
276    /// As for [`new_from_usize`](Self::new_from_usize), a value has the same bytes on every
277    /// target.
278    pub fn new_from_isize(value: isize, byte_order: ByteOrder) -> Self {
279        Self {
280            negative: value < 0,
281            ..Self::new_from_usize(value.unsigned_abs(), byte_order)
282        }
283    }
284
285    /// Creates a non-negative number from the UTF-8 bytes of a string, read in `byte_order`,
286    /// without the high zero bytes (see [`new`](Self::new)).
287    ///
288    /// The string is not parsed as digits: its bytes are the number, the way textbook RSA
289    /// turns a message into an integer, so a leading `'-'` is the byte `0x2D`, not a sign.
290    /// In big-endian order the first byte of the string is the most significant one, and
291    /// leading `'\0'` characters are dropped as zero bytes; in little-endian order the first
292    /// byte is the least significant one, and trailing `'\0'` characters are dropped. An empty
293    /// string gives an empty `value`.
294    ///
295    /// # Examples
296    ///
297    /// ```
298    /// use a::math::numbers::{ByteOrder, Number};
299    ///
300    /// // 0x31_32_33 = 3,224,115, not 123.
301    /// let n = Number::new_from_str("123", ByteOrder::BigEndian);
302    /// assert_eq!(n.value, [0x31, 0x32, 0x33]);
303    /// ```
304    pub fn new_from_str(value: &str, byte_order: ByteOrder) -> Self {
305        Self::new(value.as_bytes().to_vec(), byte_order)
306    }
307
308    /// Returns whether the number is below zero.
309    ///
310    /// It reads `negative`, as the constructors and the operators keep it: never set for zero. A
311    /// number built directly from its fields is stored as given, and a zero magnitude with
312    /// `negative` set says it is negative here, though it is zero to the comparisons and the
313    /// arithmetic, and to [`is_zero`](Self::is_zero) and [`signum`](Self::signum).
314    ///
315    /// # Examples
316    ///
317    /// ```
318    /// use a::math::numbers::{ByteOrder, Number};
319    ///
320    /// assert!(Number::new_from_i32(-7, ByteOrder::BigEndian).is_negative());
321    /// assert!(!Number::new_from_i32(7, ByteOrder::BigEndian).is_negative());
322    /// assert!(!Number::new_from_i32(0, ByteOrder::BigEndian).is_negative());
323    /// ```
324    pub fn is_negative(&self) -> bool {
325        self.negative
326    }
327
328    /// Returns the order of the bytes in `value`.
329    ///
330    /// # Examples
331    ///
332    /// ```
333    /// use a::math::numbers::{ByteOrder, Number};
334    ///
335    /// let n = Number::new_from_u8(7, ByteOrder::LittleEndian);
336    /// assert!(n.byte_order() == ByteOrder::LittleEndian);
337    /// ```
338    pub fn byte_order(&self) -> ByteOrder {
339        self.byte_order
340    }
341}
342
343impl Clone for Number {
344    /// Returns a copy of the number, its bytes exactly as they are stored, high zero bytes
345    /// included, in a new vector of their length.
346    #[inline]
347    fn clone(&self) -> Self {
348        Number {
349            value: self.value.clone(),
350            negative: self.negative,
351            byte_order: self.byte_order,
352        }
353    }
354
355    /// Makes `self` a copy of `source`, in the vector of `self` when it has room.
356    #[inline]
357    fn clone_from(&mut self, source: &Self) {
358        self.value.clone_from(&source.value);
359        self.negative = source.negative;
360        self.byte_order = source.byte_order;
361    }
362}
363
364impl Default for Number {
365    /// Returns zero, little-endian, with an empty vector, which allocates nothing: `mem::take` of
366    /// a number leaves this behind. Little-endian is the order of the limbs of the arithmetic on
367    /// every target this crate has kernels for: the kernels read and write its bytes as limbs as
368    /// they are, where big-endian bytes are turned around.
369    ///
370    /// # Examples
371    ///
372    /// ```
373    /// use a::math::numbers::{ByteOrder, Number};
374    ///
375    /// let zero = Number::default();
376    /// assert!(zero.is_zero());
377    /// assert!(zero.byte_order() == ByteOrder::LittleEndian);
378    /// assert_eq!(zero.value.capacity(), 0);
379    /// ```
380    #[inline]
381    fn default() -> Self {
382        Number {
383            value: Vec::new(),
384            negative: false,
385            byte_order: ByteOrder::LittleEndian,
386        }
387    }
388}
389
390impl fmt::Debug for Number {
391    /// Writes the number in decimal, as [`Display`](fmt::Display) does, so that numbers that are
392    /// equal look alike; the bytes are in the public fields.
393    ///
394    /// # Examples
395    ///
396    /// ```
397    /// use a::math::numbers::{ByteOrder, Number};
398    ///
399    /// let n = Number::new_from_i32(-1000, ByteOrder::BigEndian);
400    /// assert_eq!(format!("{n:?}"), "-1000");
401    /// assert_eq!(format!("{:?}", [n]), "[-1000]");
402    /// ```
403    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404        fmt::Display::fmt(self, f)
405    }
406}