core_models/abstractions/
bit.rs

1//! # Bit Manipulation and Machine Integer Utilities
2//!
3//! This module provides utilities for working with individual bits and machine integer types.
4//! It defines a [`Bit`] enum to represent a single bit (`0` or `1`) along with convenient
5//! conversion implementations between `Bit`, [`bool`], and various primitive integer types.
6//!
7//! In addition, the module introduces the [`MachineInteger`] trait which abstracts over
8//! integer types, providing associated constants:
9//!
10//! - `BITS`: The size of the integer type in bits.
11//! - `SIGNED`: A flag indicating whether the type is signed.
12//!
13//! The [`Bit`] type includes methods for extracting the value of a specific bit from an integer.
14//! For example, [`Bit::of_int`] returns the bit at a given position for a provided integer,
15//! handling both positive and negative values (assuming a two's complement representation).
16//!
17//! # Examples
18//!
19//! ```rust
20//! use core_models::abstractions::bit::{Bit, MachineInteger};
21//!
22//! // Extract the 3rd bit (0-indexed) from an integer.
23//! let bit = Bit::of_int(42, 2);
24//! println!("The extracted bit is: {:?}", bit);
25//!
26//! // Convert Bit to a primitive integer type.
27//! let num: u8 = bit.into();
28//! println!("As an integer: {}", num);
29//! ```
30//!
31//! [`bool`]: https://doc.rust-lang.org/std/primitive.bool.html
32//! [`Bit::of_int`]: enum.Bit.html#method.of_int
33
34/// Represent a bit: `0` or `1`.
35#[derive(Copy, Clone, Eq, PartialEq, Debug)]
36pub enum Bit {
37    Zero,
38    One,
39}
40
41macro_rules! generate_from_bit_impls {
42    ($($ty:ident),*) => {
43        $(impl From<Bit> for $ty {
44            fn from(bit: Bit) -> Self {
45                bool::from(bit) as $ty
46            }
47        })*
48    };
49}
50generate_from_bit_impls!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);
51
52impl From<Bit> for bool {
53    fn from(bit: Bit) -> Self {
54        match bit {
55            Bit::Zero => false,
56            Bit::One => true,
57        }
58    }
59}
60
61impl From<bool> for Bit {
62    fn from(b: bool) -> Bit {
63        match b {
64            false => Bit::Zero,
65            true => Bit::One,
66        }
67    }
68}
69
70/// A trait for types that represent machine integers.
71#[hax_lib::attributes]
72pub trait MachineInteger {
73    /// The size of this integer type in bits.
74    #[hax_lib::requires(true)]
75    #[hax_lib::ensures(|bits| bits >= 8)]
76    fn bits() -> u32;
77
78    /// The signedness of this integer type.
79    const SIGNED: bool;
80}
81
82macro_rules! generate_machine_integer_impls {
83    ($($ty:ident),*) => {
84        $(#[hax_lib::exclude]impl MachineInteger for $ty {
85            fn bits() -> u32 { $ty::BITS }
86            #[allow(unused_comparisons)]
87            const SIGNED: bool = $ty::MIN < 0;
88        })*
89    };
90}
91generate_machine_integer_impls!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);
92
93#[hax_lib::fstar::replace(
94    r"
95instance impl_MachineInteger_poly (t: inttype): t_MachineInteger (int_t t) =
96  { f_bits = (fun () -> mk_u32 (bits t));
97    f_bits_pre = (fun () -> True);
98    f_bits_post = (fun () r -> r == mk_u32 (bits t));
99    f_SIGNED = signed t }
100"
101)]
102const _: () = {};
103
104#[hax_lib::exclude]
105impl Bit {
106    fn of_raw_int(x: u128, nth: u32) -> Self {
107        if x / 2u128.pow(nth) % 2 == 1 {
108            Self::One
109        } else {
110            Self::Zero
111        }
112    }
113
114    pub fn of_int<T: Into<i128> + MachineInteger>(x: T, nth: u32) -> Bit {
115        let x: i128 = x.into();
116        if x >= 0 {
117            Self::of_raw_int(x as u128, nth)
118        } else {
119            Self::of_raw_int((2i128.pow(T::bits()) + x) as u128, nth)
120        }
121    }
122}