Skip to main content

a/math/numbers/
prim.rs

1//! The arithmetic operators with a primitive integer on either side: `a + 1`, `&a * 10`,
2//! `a % 7u64`, `1i32 - &a`, `a -= 5i128`, and so on for `+`, `-`, `*`, `/` and `%` and their
3//! assignments, with every primitive integer type.
4//!
5//! Each computes what the operator computes with the integer made a [`Number`]: the same results,
6//! byte orders and panics. With the number on the left, the result is in its byte order, and built
7//! in its vector when it is owned and has room, as with two numbers. With the integer on the left,
8//! it is in the byte order of the number on the right, the only one there is: `1 - &a` is `-(&a -
9//! 1)`, and `10 / &a` is the integer as a number in `a`'s byte order divided by `a`.
10//!
11//! `+` and `-`, and `*` by an integer of up to 64 bits, have paths of their own, which change the
12//! number's bytes in place, in one pass, without reading it into limbs: a sum carries out of the
13//! integer's bytes only as far as the number's bytes are all ones, and a product of a number of up
14//! to 16 bytes is computed in registers, and of a longer little-endian one by the kernel of the
15//! multiplication for one limb (a longer big-endian one multiplies as two numbers do). Measured on an Apple M4 Max with `a` of 1 KiB, `a += 1` took 9 cycles
16//! against 29 for `a += &one` with `one` a number, and `a *= 10` 135 against 260 for the product of
17//! two numbers before it took the same path (GMP's `mpz_add_ui` and `mpz_mul_ui`: 13 and 122). The
18//! others make the integer a number in a vector of 16 bytes that each thread keeps for it, so that
19//! they allocate nothing for it; a division costs the same with it as with a number.
20
21use super::add::{read, read_small, write, write_small};
22use super::cmp::parts;
23use super::mul::mul_1_bytes;
24use super::{ByteOrder, Number};
25use core::cell::Cell;
26use core::mem;
27use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign};
28
29thread_local! {
30    /// The vector that the integer operand of an operator is made a number in, kept between
31    /// operators so that it is allocated once in each thread.
32    static SCRATCH: Cell<Vec<u8>> = const { Cell::new(Vec::new()) };
33}
34
35/// Runs `f` on the integer of sign `negative` and magnitude `m` as a number in `order`, in the
36/// shortest form, built in the thread's vector, which it returns to the thread afterwards.
37///
38/// An operator that panics, dividing by zero, drops the vector; the next takes a new one.
39#[inline(always)]
40fn with_number<R>(negative: bool, m: u128, order: ByteOrder, f: impl FnOnce(&Number) -> R) -> R {
41    let mut value = SCRATCH.take();
42    value.clear();
43    let len = 16 - (m | 1).leading_zeros() as usize / 8;
44    match order {
45        ByteOrder::BigEndian => value.extend_from_slice(&m.to_be_bytes()[16 - len..]),
46        ByteOrder::LittleEndian => value.extend_from_slice(&m.to_le_bytes()[..len]),
47    }
48    let n = Number {
49        value,
50        negative: negative && m != 0,
51        byte_order: order,
52    };
53    let result = f(&n);
54    SCRATCH.set(n.value);
55    result
56}
57
58/// A copy of the significant bytes of `a`, its sign and byte order, in a new vector with room for
59/// `spare` bytes more: what the operators with a borrowed number change in place.
60#[inline(always)]
61fn significant_copy(a: &Number, spare: usize) -> Number {
62    let s = a.significant();
63    let bytes = if a.byte_order == ByteOrder::BigEndian {
64        &a.value[a.value.len() - s..]
65    } else {
66        &a.value[..s]
67    };
68    let mut value = Vec::with_capacity(s + spare);
69    value.extend_from_slice(bytes);
70    Number {
71        value,
72        negative: a.negative && s != 0,
73        byte_order: a.byte_order,
74    }
75}
76
77/// Makes `a` the sum of `a` and the integer of sign `negative` and magnitude `m`, in the shortest
78/// form, in its vector when it has room.
79///
80/// A number of up to 16 bytes is added in registers, as the addition of two numbers does. A longer
81/// one is larger than the integer: the integer's 16 bytes are added to its 16 lowest, or subtracted
82/// from them, and the carry or borrow taken up through its bytes while they are all ones or all
83/// zeros; a carry out of the top byte makes it one byte longer, and a borrow can make its top bytes
84/// zero.
85#[inline(never)]
86fn add_in_place(a: &mut Number, negative: bool, m: u128) {
87    let s = a.significant();
88    let be = a.byte_order == ByteOrder::BigEndian;
89    if s <= 16 {
90        let start = if be { a.value.len() - s } else { 0 };
91        // SAFETY: the significant bytes are at most 16.
92        let x = unsafe { read_small(&a.value[start..start + s], a.byte_order) };
93        let negative_a = a.negative && s != 0;
94        let (magnitude, carry, sign) = if negative_a == negative {
95            let (sum, carry) = x.overflowing_add(m);
96            (sum, carry, negative_a)
97        } else if x >= m {
98            (x - m, false, negative_a)
99        } else {
100            (m - x, false, negative)
101        };
102        let len = if carry {
103            17
104        } else {
105            16 - (magnitude | 1).leading_zeros() as usize / 8
106        };
107        a.value.clear();
108        a.value.reserve(len);
109        // SAFETY: the vector has room for the `len` bytes, from 1 to 17, all of which are written
110        // before the length is set.
111        unsafe {
112            write_small(
113                a.value.as_mut_ptr(),
114                a.byte_order,
115                magnitude as u64,
116                (magnitude >> 64) as u64,
117                len,
118            );
119            a.value.set_len(len);
120        }
121        a.negative = sign && (magnitude != 0 || carry);
122        return;
123    }
124    if s != a.value.len() {
125        super::sign::trim(a);
126    }
127    let subtract = a.negative != negative;
128    let v = &mut a.value;
129    let p = v.as_mut_ptr();
130    // SAFETY: the magnitude has `s > 16` bytes: its lowest 16 are the last big-endian and the first
131    // little-endian, and byte `i < s` from the least significant one is at `s - 1 - i` big-endian
132    // and at `i` little-endian.
133    let (top_changed, carried) = unsafe {
134        let low = if be { p.add(s - 16) } else { p };
135        let x = if be {
136            u128::from_be_bytes(read(low))
137        } else {
138            u128::from_le_bytes(read(low))
139        };
140        let (y, mut c) = if subtract {
141            x.overflowing_sub(m)
142        } else {
143            x.overflowing_add(m)
144        };
145        write(low, if be { y.to_be_bytes() } else { y.to_le_bytes() });
146        let mut i = 16;
147        while c && i < s {
148            let b = if be { p.add(s - 1 - i) } else { p.add(i) };
149            (*b, c) = if subtract {
150                (*b).overflowing_sub(1)
151            } else {
152                (*b).overflowing_add(1)
153            };
154            i += 1;
155        }
156        (i >= s - 1, c)
157    };
158    if carried {
159        // All ones up to the top: one byte more, 1.
160        if be {
161            v.insert(0, 1);
162        } else {
163            v.push(1);
164        }
165    } else if subtract && top_changed {
166        super::sign::trim(a);
167    }
168}
169
170/// The product of the `s` significant bytes of a magnitude at `x` by `m` in registers, for `s` up
171/// to 16, in `order`: its three limbs and its length.
172///
173/// # Safety
174///
175/// The `s` bytes at `x` must be valid for reads.
176#[inline(always)]
177unsafe fn small_product(x: &[u8], order: ByteOrder, m: u64) -> ([u64; 3], usize) {
178    // SAFETY: the bytes are at most 16, as the caller guarantees.
179    let x = unsafe { read_small(x, order) };
180    let low = u128::from(x as u64) * u128::from(m);
181    let high = u128::from((x >> 64) as u64) * u128::from(m) + (low >> 64);
182    let limbs = [low as u64, high as u64, (high >> 64) as u64];
183    let len = if limbs[2] != 0 {
184        24 - limbs[2].leading_zeros() as usize / 8
185    } else {
186        16 - ((u128::from(limbs[1]) << 64) | u128::from(limbs[0]) | 1).leading_zeros() as usize / 8
187    };
188    (limbs, len)
189}
190
191/// Writes the product of [`small_product`], of `len` bytes, at `p` in `order`.
192///
193/// # Safety
194///
195/// `p` must be valid for writing `len` bytes, from 1 to 24.
196#[inline(always)]
197unsafe fn write_small_product(p: *mut u8, order: ByteOrder, [l0, l1, l2]: [u64; 3], len: usize) {
198    // SAFETY: as the caller guarantees: up to 16 bytes as the addition writes them; above, the two
199    // low limbs and the `len - 16` bytes of the top one, from 1 to 8.
200    unsafe {
201        if len <= 16 {
202            write_small(p, order, l0, l1, len);
203        } else if order == ByteOrder::BigEndian {
204            write(p.add(len - 8), l0.to_be_bytes());
205            write(p.add(len - 16), l1.to_be_bytes());
206            write_small(p, order, l2, 0, len - 16);
207        } else {
208            write(p, l0.to_le_bytes());
209            write(p.add(8), l1.to_le_bytes());
210            write_small(p.add(16), order, l2, 0, len - 16);
211        }
212    }
213}
214
215/// The significant bytes of `a`.
216#[inline(always)]
217fn significant_bytes(a: &Number, s: usize) -> &[u8] {
218    if a.byte_order == ByteOrder::BigEndian {
219        &a.value[a.value.len() - s..]
220    } else {
221        &a.value[..s]
222    }
223}
224
225/// The whole limbs of the little-endian magnitude `x` times `m`, written at `dst`, which may be
226/// `x`, by the kernel of the multiplication for one limb; returns the carry out of them.
227///
228/// # Safety
229///
230/// `x` must hold at least 8 bytes; `dst` must be `x` or apart from it, and valid for writing the
231/// `x.len() / 8 * 8` bytes of the limbs.
232#[inline(always)]
233unsafe fn limbs_le(dst: *mut u8, x: *const u8, s: usize, m: u64) -> u64 {
234    // SAFETY: as the caller guarantees; the kernel reads limb `i` before it writes it.
235    unsafe { mul_1_bytes(dst, x, s / 8, m) }
236}
237
238/// The bytes of the little-endian magnitude `x` above its whole limbs times `m`, with the `carry`
239/// out of the limbs: the product's top bytes and their count, at least `x.len() % 8` and at most
240/// `x.len() % 8 + 8`; none when the magnitude is whole limbs and the carry zero, and the top limb
241/// below them is then not zero, as the product is at least `x`.
242#[inline(always)]
243fn top_le(x: &[u8], m: u64, carry: u64) -> (u128, usize) {
244    let top = x[x.len() / 8 * 8..]
245        .iter()
246        .rev()
247        .fold(0u64, |t, &b| (t << 8) | u64::from(b));
248    let top = u128::from(top) * u128::from(m) + u128::from(carry);
249    (top, (128 - top.leading_zeros() as usize).div_ceil(8))
250}
251
252/// Makes `a` the product of `a` and the integer of sign `negative` and magnitude `m`, in the
253/// shortest form, as the multiplication of two numbers places its product: in the vector of `a`
254/// when it has room for it, else in `donor` when that has room, which then gets the vector of `a`,
255/// and otherwise in one new vector. Returns `false`, `a` unchanged, for a big-endian number of
256/// more than 16 bytes, which the general path of the multiplication multiplies faster.
257///
258/// A number of up to 16 bytes is multiplied in registers. A longer little-endian one is multiplied
259/// in place by the kernel of the multiplication for one limb, its bytes read as limbs as they are,
260/// in one pass. Big-endian, its limbs would move up by the bytes the product gains, a second pass:
261/// measured on an Apple M4 Max as `a *= &b` with `b` of one byte, 1 KiB took 370 cycles so against
262/// 285 by the general path.
263#[inline(never)]
264fn mul_in_place(a: &mut Number, negative: bool, m: u64, donor: Option<&mut Vec<u8>>) -> bool {
265    let s = a.significant();
266    let order = a.byte_order;
267    let sign = a.negative != negative;
268    if s == 0 || m == 0 {
269        place(a, donor, 1);
270        a.value.clear();
271        a.value.push(0);
272        a.negative = false;
273        return true;
274    }
275    if s <= 16 {
276        // SAFETY: the significant bytes are at most 16.
277        let (limbs, len) = unsafe { small_product(significant_bytes(a, s), order, m) };
278        place(a, donor, len);
279        a.value.clear();
280        // SAFETY: the vector has room for the `len` bytes, all of which are written before the
281        // length is set.
282        unsafe {
283            write_small_product(a.value.as_mut_ptr(), order, limbs, len);
284            a.value.set_len(len);
285        }
286        a.negative = sign;
287        return true;
288    }
289    if order == ByteOrder::BigEndian {
290        return false;
291    }
292    a.value.truncate(s);
293    let p = a.value.as_mut_ptr();
294    // SAFETY: the limbs are written over themselves, inside the `s` bytes of the magnitude, the
295    // bytes above them left as they are.
296    let carry = unsafe { limbs_le(p, p, s, m) };
297    let (top, t) = top_le(&a.value, m, carry);
298    let full = s / 8 * 8;
299    place(a, donor, full + t);
300    a.value.truncate(full);
301    a.value.extend_from_slice(&top.to_le_bytes()[..t]);
302    a.negative = sign;
303    true
304}
305
306/// The product of `a` and the integer of sign `negative` and magnitude `m` in a new vector, or in
307/// `donor` when that has room for it; `None` for a big-endian number of more than 16 bytes, as
308/// [`mul_in_place`] says.
309#[inline(never)]
310fn mul_into(a: &Number, negative: bool, m: u64, donor: Option<&mut Vec<u8>>) -> Option<Number> {
311    let s = a.significant();
312    let order = a.byte_order;
313    if s == 0 || m == 0 || s <= 16 {
314        // Zero, one byte, or a product in registers, in `donor`'s vector when it has room.
315        let (limbs, len) = if s == 0 || m == 0 {
316            ([0; 3], 1)
317        } else {
318            // SAFETY: the significant bytes are at most 16.
319            unsafe { small_product(significant_bytes(a, s), order, m) }
320        };
321        let mut value = match donor {
322            Some(d) if d.capacity() >= len => mem::take(d),
323            _ => Vec::with_capacity(len),
324        };
325        value.clear();
326        // SAFETY: the vector has room for the `len` bytes, all of which are written before the
327        // length is set.
328        unsafe {
329            write_small_product(value.as_mut_ptr(), order, limbs, len);
330            value.set_len(len);
331        }
332        return Some(Number {
333            value,
334            negative: (a.negative && s != 0) != negative && len > 0 && limbs != [0; 3],
335            byte_order: order,
336        });
337    }
338    if order == ByteOrder::BigEndian {
339        return None;
340    }
341    let x = significant_bytes(a, s);
342    // The product's whole limbs go to `donor`'s vector when it has room for them, and stay there
343    // when it has room for the product too; otherwise to a new vector with room for the longest
344    // product, `s + 8 - (zero bytes at the top of `m`)` bytes.
345    let most = s + 8 - m.leading_zeros() as usize / 8;
346    let mut value = match donor {
347        Some(d) if d.capacity() >= s => mem::take(d),
348        _ => Vec::with_capacity(most),
349    };
350    value.clear();
351    let full = s / 8 * 8;
352    // SAFETY: the vector has room for the `full` bytes of the limbs, apart from `a`'s; they are
353    // written before the length is set.
354    unsafe {
355        let carry = limbs_le(value.as_mut_ptr(), x.as_ptr(), s, m);
356        value.set_len(full);
357        let (top, t) = top_le(x, m, carry);
358        if value.capacity() < full + t {
359            // The donor's vector had room for the limbs only.
360            let mut v = Vec::with_capacity(most);
361            v.extend_from_slice(&value);
362            value = v;
363        }
364        value.extend_from_slice(&top.to_le_bytes()[..t]);
365    }
366    Some(Number {
367        value,
368        negative: (a.negative && s != 0) != negative,
369        byte_order: order,
370    })
371}
372
373/// Gives `a` a vector with room for `len` bytes, its own bytes kept, as the multiplication of two
374/// numbers places its product: its own vector when it has room; else `donor`'s when that has room,
375/// which then gets the vector of `a`; else its own, grown into one new vector.
376#[inline(always)]
377fn place(a: &mut Number, donor: Option<&mut Vec<u8>>, len: usize) {
378    if a.value.capacity() >= len {
379        return;
380    }
381    match donor {
382        Some(d) if d.capacity() >= len => {
383            d.clear();
384            d.extend_from_slice(&a.value);
385            mem::swap(&mut a.value, d);
386        }
387        _ => a.value.reserve_exact(len - a.value.len()),
388    }
389}
390
391/// `a *= m` for the multiplication of two numbers, one of which has one limb, `m` with the sign
392/// `negative`, as [`mul_in_place`] does it; `false`, `a` unchanged, when the general path is to.
393#[inline(always)]
394pub(super) fn times_limb(
395    a: &mut Number,
396    negative: bool,
397    m: u64,
398    donor: Option<&mut Vec<u8>>,
399) -> bool {
400    mul_in_place(a, negative, m, donor)
401}
402
403/// `&a * m` for the multiplication of two numbers, one of which has one limb, `m` with the sign
404/// `negative`, as [`mul_into`] does it; `None` when the general path is to.
405#[inline(always)]
406pub(super) fn copy_times_limb(
407    a: &Number,
408    negative: bool,
409    m: u64,
410    donor: Option<&mut Vec<u8>>,
411) -> Option<Number> {
412    mul_into(a, negative, m, donor)
413}
414
415// Each operator with the integer of sign `negative` and magnitude `m` on the right: in place on
416// `a`, and on a borrowed `a`, into a new number.
417
418/// `a += m`.
419#[inline(always)]
420fn add_assign(a: &mut Number, negative: bool, m: u128) {
421    add_in_place(a, negative, m);
422}
423
424/// `&a + m`, in a copy of `a` with room for the sum.
425#[inline(always)]
426fn add_ref(a: &Number, negative: bool, m: u128) -> Number {
427    let mut sum = significant_copy(a, 17);
428    add_in_place(&mut sum, negative, m);
429    sum
430}
431
432/// `a -= m`, as `a += -m`.
433#[inline(always)]
434fn sub_assign(a: &mut Number, negative: bool, m: u128) {
435    add_in_place(a, !negative, m);
436}
437
438/// `&a - m`, as `&a + -m`.
439#[inline(always)]
440fn sub_ref(a: &Number, negative: bool, m: u128) -> Number {
441    add_ref(a, !negative, m)
442}
443
444/// `a *= m`: in place for `m` of up to 64 bits when [`mul_in_place`] can, by the product of two
445/// numbers otherwise.
446#[inline(always)]
447fn mul_assign(a: &mut Number, negative: bool, m: u128) {
448    if m >> 64 != 0 || !mul_in_place(a, negative, m as u64, None) {
449        with_number(negative, m, ByteOrder::LittleEndian, |b| *a *= b);
450    }
451}
452
453/// `&a * m`: into a new vector for `m` of up to 64 bits when [`mul_into`] can, by the product of
454/// two numbers otherwise.
455#[inline(always)]
456fn mul_ref(a: &Number, negative: bool, m: u128) -> Number {
457    if m >> 64 == 0
458        && let Some(product) = mul_into(a, negative, m as u64, None)
459    {
460        return product;
461    }
462    with_number(negative, m, ByteOrder::LittleEndian, |b| a * b)
463}
464
465/// `a /= m`, by the division of two numbers.
466#[inline(always)]
467#[track_caller]
468fn div_assign(a: &mut Number, negative: bool, m: u128) {
469    with_number(negative, m, ByteOrder::LittleEndian, |b| *a /= b);
470}
471
472/// `&a / m`, by the division of two numbers.
473#[inline(always)]
474#[track_caller]
475fn div_ref(a: &Number, negative: bool, m: u128) -> Number {
476    with_number(negative, m, ByteOrder::LittleEndian, |b| a / b)
477}
478
479/// `a %= m`, by the division of two numbers, whose remainder alone by one limb takes eight limbs
480/// a step.
481#[inline(always)]
482#[track_caller]
483fn rem_assign(a: &mut Number, negative: bool, m: u128) {
484    with_number(negative, m, ByteOrder::LittleEndian, |b| *a %= b);
485}
486
487/// `&a % m`, by the division of two numbers.
488#[inline(always)]
489#[track_caller]
490fn rem_ref(a: &Number, negative: bool, m: u128) -> Number {
491    with_number(negative, m, ByteOrder::LittleEndian, |b| a % b)
492}
493
494/// The operators of the traits `$op`/`$assign` (methods `$f`/`$f_assign`) between numbers and
495/// the primitive integer types, with the integer on the right, by the functions `$assign_f`
496/// and `$ref_f`.
497macro_rules! right {
498    ($op:ident $f:ident $assign:ident $f_assign:ident $sym:literal $assign_f:ident $ref_f:ident: $($t:ident),*) => {$(
499        impl $op<$t> for &Number {
500            type Output = Number;
501
502            #[doc = concat!("Returns `self ", $sym, " rhs`, as with `rhs` a number.")]
503            #[inline]
504            #[track_caller]
505            fn $f(self, rhs: $t) -> Number {
506                let (negative, m) = parts!(rhs, $t);
507                $ref_f(self, negative, m)
508            }
509        }
510
511        impl $op<$t> for Number {
512            type Output = Number;
513
514            #[doc = concat!("Returns `self ", $sym, " rhs`, as with `rhs` a number, in the vector of `self` when it has room.")]
515            #[inline]
516            #[track_caller]
517            fn $f(mut self, rhs: $t) -> Number {
518                let (negative, m) = parts!(rhs, $t);
519                $assign_f(&mut self, negative, m);
520                self
521            }
522        }
523
524        impl $assign<$t> for Number {
525            #[doc = concat!("Makes `self` `self ", $sym, " rhs`, as with `rhs` a number, in the vector of `self` when it has room.")]
526            #[inline]
527            #[track_caller]
528            fn $f_assign(&mut self, rhs: $t) {
529                let (negative, m) = parts!(rhs, $t);
530                $assign_f(self, negative, m);
531            }
532        }
533    )*};
534}
535
536/// The commutative operators `+` and `*` with the integer on the left: the same with the operands
537/// the other way round.
538macro_rules! left_commutative {
539    ($op:ident $f:ident $sym:literal: $($t:ident),*) => {$(
540        impl $op<Number> for $t {
541            type Output = Number;
542
543            #[doc = concat!("Returns `self ", $sym, " rhs`, as `rhs ", $sym, " self`, in the vector of `rhs` when it has room.")]
544            #[inline]
545            fn $f(self, rhs: Number) -> Number {
546                rhs.$f(self)
547            }
548        }
549
550        impl $op<&Number> for $t {
551            type Output = Number;
552
553            #[doc = concat!("Returns `self ", $sym, " rhs`, as `rhs ", $sym, " self`.")]
554            #[inline]
555            fn $f(self, rhs: &Number) -> Number {
556                rhs.$f(self)
557            }
558        }
559    )*};
560}
561
562/// `-`, `/` and `%` with the integer on the left: `self - rhs` is `-(rhs - self)`, and the others
563/// the integer as a number in the byte order of `rhs` divided by `rhs`.
564macro_rules! left {
565    ($($t:ident),*) => {$(
566        impl Sub<Number> for $t {
567            type Output = Number;
568
569            /// Returns `self - rhs`, as `-(rhs - self)`, in the vector of `rhs` when it has room.
570            #[inline]
571            fn sub(self, rhs: Number) -> Number {
572                -(rhs - self)
573            }
574        }
575
576        impl Sub<&Number> for $t {
577            type Output = Number;
578
579            /// Returns `self - rhs`, as `-(rhs - self)`.
580            #[inline]
581            fn sub(self, rhs: &Number) -> Number {
582                -(rhs - self)
583            }
584        }
585
586        impl Div<Number> for $t {
587            type Output = Number;
588
589            /// Returns `self / rhs`, as with `self` a number in the byte order of `rhs`, in the
590            /// vector of `rhs` when it has room.
591            #[inline]
592            #[track_caller]
593            fn div(self, rhs: Number) -> Number {
594                let (negative, m) = parts!(self, $t);
595                let order = rhs.byte_order;
596                with_number(negative, m, order, |a| a / rhs)
597            }
598        }
599
600        impl Div<&Number> for $t {
601            type Output = Number;
602
603            /// Returns `self / rhs`, as with `self` a number in the byte order of `rhs`.
604            #[inline]
605            #[track_caller]
606            fn div(self, rhs: &Number) -> Number {
607                let (negative, m) = parts!(self, $t);
608                with_number(negative, m, rhs.byte_order, |a| a / rhs)
609            }
610        }
611
612        impl Rem<Number> for $t {
613            type Output = Number;
614
615            /// Returns `self % rhs`, as with `self` a number in the byte order of `rhs`, in the
616            /// vector of `rhs` when it has room.
617            #[inline]
618            #[track_caller]
619            fn rem(self, rhs: Number) -> Number {
620                let (negative, m) = parts!(self, $t);
621                let order = rhs.byte_order;
622                with_number(negative, m, order, |a| a % rhs)
623            }
624        }
625
626        impl Rem<&Number> for $t {
627            type Output = Number;
628
629            /// Returns `self % rhs`, as with `self` a number in the byte order of `rhs`.
630            #[inline]
631            #[track_caller]
632            fn rem(self, rhs: &Number) -> Number {
633                let (negative, m) = parts!(self, $t);
634                with_number(negative, m, rhs.byte_order, |a| a % rhs)
635            }
636        }
637    )*};
638}
639
640/// Every operator with every primitive integer type.
641macro_rules! all {
642    ($($t:ident),*) => {
643        right!(Add add AddAssign add_assign "+" add_assign add_ref: $($t),*);
644        right!(Sub sub SubAssign sub_assign "-" sub_assign sub_ref: $($t),*);
645        right!(Mul mul MulAssign mul_assign "*" mul_assign mul_ref: $($t),*);
646        right!(Div div DivAssign div_assign "/" div_assign div_ref: $($t),*);
647        right!(Rem rem RemAssign rem_assign "%" rem_assign rem_ref: $($t),*);
648        left_commutative!(Add add "+": $($t),*);
649        left_commutative!(Mul mul "*": $($t),*);
650        left!($($t),*);
651    };
652}
653
654all!(
655    u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
656);