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::{
17    BorrowingSub, CarryingAdd, OverflowingAdd, OverflowingSub, ToBytes, WideningMul,
18};
19
20c0nst::c0nst! {
21    /// Const-friendly aggregate trait bundling the arithmetic, bit,
22    /// shift, and byte-conversion capabilities every limb type has to
23    /// carry to serve as a `FixedUInt`'s `T`.
24    ///
25    /// `*Assign` bounds are added explicitly: external `PrimBits` /
26    /// `PrimInt` cover the by-value bit/shift ops (the CT-friendly
27    /// core) but not their `*Assign` counterparts, which we rely on
28    /// in `fixeduint.rs` (the per-limb loops use `|=` / `^=` / `<<=`
29    /// / `>>=` / `&=` etc. on `T`).
30    pub c0nst trait ConstMachineWord:
31        [c0nst] PrimInt +
32        [c0nst] OverflowingAdd +
33        [c0nst] OverflowingSub +
34        [c0nst] CarryingAdd +
35        [c0nst] BorrowingSub +
36        [c0nst] ToBytes +
37        [c0nst] WideningMul +
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] core::ops::AddAssign +
44        [c0nst] core::ops::SubAssign +
45        [c0nst] From<u8>
46    {
47        type ConstDoubleWord: [c0nst] PrimInt
48            + [c0nst] core::ops::BitAndAssign
49            + [c0nst] core::ops::BitOrAssign
50            + [c0nst] core::ops::AddAssign
51            + [c0nst] core::ops::Mul<Output = Self::ConstDoubleWord>
52            + [c0nst] core::ops::BitAnd<Output = Self::ConstDoubleWord>
53            + [c0nst] core::ops::Shr<usize, Output = Self::ConstDoubleWord>;
54        fn to_double(self) -> Self::ConstDoubleWord;
55        fn from_double(word: Self::ConstDoubleWord) -> Self;
56    }
57
58    c0nst impl ConstMachineWord for u8 {
59        type ConstDoubleWord = u16;
60        fn to_double(self) -> u16 { self as u16 }
61        fn from_double(word: u16) -> u8 { word as u8 }
62    }
63    c0nst impl ConstMachineWord for u16 {
64        type ConstDoubleWord = u32;
65        fn to_double(self) -> u32 { self as u32 }
66        fn from_double(word: u32) -> u16 { word as u16 }
67    }
68    c0nst impl ConstMachineWord for u32 {
69        type ConstDoubleWord = u64;
70        fn to_double(self) -> u64 { self as u64 }
71        fn from_double(word: u64) -> u32 { word as u32 }
72    }
73    c0nst impl ConstMachineWord for u64 {
74        type ConstDoubleWord = u128;
75        fn to_double(self) -> u128 { self as u128 }
76        fn from_double(word: u128) -> u64 { word as u64 }
77    }
78}
79
80/// Represents a CPU native word, from 8-bit to 64-bit, with corresponding
81/// double-word to hold multiplication/division products.
82///
83/// This trait is intentionally sealed via the `ConstMachineWord` supertrait,
84/// as custom implementations are not supported.
85pub trait MachineWord:
86    ConstMachineWord<ConstDoubleWord = Self::DoubleWord>
87    + core::hash::Hash
88    + const_num_traits::ToPrimitive
89{
90    type DoubleWord: PrimInt;
91}
92
93impl MachineWord for u8 {
94    type DoubleWord = u16;
95}
96impl MachineWord for u16 {
97    type DoubleWord = u32;
98}
99impl MachineWord for u32 {
100    type DoubleWord = u64;
101}
102impl MachineWord for u64 {
103    type DoubleWord = u128;
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109
110    c0nst::c0nst! {
111        pub c0nst fn to_double<T: [c0nst] ConstMachineWord>(a: T) -> T::ConstDoubleWord {
112            a.to_double()
113        }
114    }
115
116    #[test]
117    fn test_constmachineword_ops() {
118        assert_eq!(to_double(200u8), 200u16);
119
120        #[cfg(feature = "nightly")]
121        {
122            const DOUBLE_RES: u16 = to_double(200u8);
123            assert_eq!(DOUBLE_RES, 200u16);
124        }
125    }
126}