Skip to main content

fixed_bigint/
machineword.rs

1// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15pub use const_num_traits::PrimInt;
16use const_num_traits::{BorrowingSub, CarryingAdd, OverflowingSub, ToBytes};
17
18c0nst::c0nst! {
19    /// Const-friendly aggregate trait bundling the arithmetic, bit,
20    /// shift, and byte-conversion capabilities every limb type has to
21    /// carry to serve as a `FixedUInt`'s `T`.
22    ///
23    /// The bit/shift `*Assign` supertraits are added explicitly:
24    /// `PrimBits`/`PrimInt` provide the by-value bit/shift ops but
25    /// not the `*Assign` counterparts, which the per-limb loops in
26    /// `fixeduint.rs`/`bit_ops_impl.rs` use (`|=` / `^=` / `<<=` /
27    /// `>>=` / `&=` on `T`). Arithmetic `*Assign` and `WideningMul`
28    /// are intentionally NOT here — no limb-loop uses `T += T` /
29    /// `T -= T`, and the crate doesn't call `T::widening_mul`
30    /// anywhere (the CarryingMul impls route through the
31    /// `ConstDoubleWord` associated type).
32    pub c0nst trait ConstMachineWord:
33        [c0nst] PrimInt +
34        [c0nst] OverflowingSub<Output = Self> +
35        [c0nst] CarryingAdd<Output = Self> +
36        [c0nst] BorrowingSub<Output = Self> +
37        [c0nst] ToBytes +
38        [c0nst] core::ops::BitAndAssign +
39        [c0nst] core::ops::BitOrAssign +
40        [c0nst] core::ops::BitXorAssign +
41        [c0nst] core::ops::ShlAssign<usize> +
42        [c0nst] core::ops::ShrAssign<usize> +
43        [c0nst] From<u8>
44    {
45        type ConstDoubleWord: [c0nst] PrimInt
46            + [c0nst] core::ops::BitAndAssign
47            + [c0nst] core::ops::AddAssign;
48        fn to_double(self) -> Self::ConstDoubleWord;
49        fn from_double(word: Self::ConstDoubleWord) -> Self;
50    }
51
52    c0nst impl ConstMachineWord for u8 {
53        type ConstDoubleWord = u16;
54        fn to_double(self) -> u16 { self as u16 }
55        fn from_double(word: u16) -> u8 { word as u8 }
56    }
57    c0nst impl ConstMachineWord for u16 {
58        type ConstDoubleWord = u32;
59        fn to_double(self) -> u32 { self as u32 }
60        fn from_double(word: u32) -> u16 { word as u16 }
61    }
62    c0nst impl ConstMachineWord for u32 {
63        type ConstDoubleWord = u64;
64        fn to_double(self) -> u64 { self as u64 }
65        fn from_double(word: u64) -> u32 { word as u32 }
66    }
67    c0nst impl ConstMachineWord for u64 {
68        type ConstDoubleWord = u128;
69        fn to_double(self) -> u128 { self as u128 }
70        fn from_double(word: u128) -> u64 { word as u64 }
71    }
72}
73
74/// Represents a CPU native word, from 8-bit to 64-bit, with corresponding
75/// double-word to hold multiplication/division products.
76///
77/// This trait is intentionally sealed via the `ConstMachineWord` supertrait,
78/// as custom implementations are not supported.
79pub trait MachineWord:
80    ConstMachineWord<ConstDoubleWord = Self::DoubleWord>
81    + core::hash::Hash
82    + const_num_traits::ToPrimitive
83{
84    type DoubleWord: PrimInt;
85}
86
87impl MachineWord for u8 {
88    type DoubleWord = u16;
89}
90impl MachineWord for u16 {
91    type DoubleWord = u32;
92}
93impl MachineWord for u32 {
94    type DoubleWord = u64;
95}
96impl MachineWord for u64 {
97    type DoubleWord = u128;
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103
104    c0nst::c0nst! {
105        pub c0nst fn to_double<T: [c0nst] ConstMachineWord>(a: T) -> T::ConstDoubleWord {
106            a.to_double()
107        }
108    }
109
110    #[test]
111    fn test_constmachineword_ops() {
112        assert_eq!(to_double(200u8), 200u16);
113
114        #[cfg(feature = "nightly")]
115        {
116            const DOUBLE_RES: u16 = to_double(200u8);
117            assert_eq!(DOUBLE_RES, 200u16);
118        }
119    }
120}