Skip to content

Instantly share code, notes, and snippets.

@lachlansneff
Created May 16, 2021 02:09
Show Gist options
  • Save lachlansneff/fc2e30d7d68f1f399723581415d7c0b7 to your computer and use it in GitHub Desktop.
Save lachlansneff/fc2e30d7d68f1f399723581415d7c0b7 to your computer and use it in GitHub Desktop.
use core::{
ops::{Shr, ShrAssign, Shl, ShlAssign, BitOr, BitOrAssign},
hash::Hash,
fmt,
};
macro_rules! impl_uint {
($int_ty:ty: [$($bits:literal),*]) => {
$(
impl Uint for u<$bits> {
type Inner = $int_ty;
const MAX: $int_ty = ((1 as $int_ty) << $bits) - 1;
const MIN: $int_ty = 0;
}
)*
};
}
impl_uint!(u8: [1, 2, 3, 4, 5, 6, 7, 8]);
impl_uint!(u16: [9, 10, 11, 12, 13, 14, 15, 16]);
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct u<const N: usize>(<Self as Uint>::Inner)
where
Self: Uint;
#[doc(hidden)]
pub trait Uint {
type Inner:
Copy + Clone
+ PartialEq + Eq
+ PartialOrd + Ord
+ Hash
+ fmt::Debug + fmt::Display
+ fmt::UpperHex + fmt::LowerHex
+ fmt::Octal + fmt::Binary;
const MAX: Self::Inner;
const MIN: Self::Inner;
}
impl<const N: usize> u<N> where Self: Uint {
/// The smallest value that can be represented by this integer type.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// assert_eq!(u::<6>::MIN, 0);
/// ```
pub const MIN: Self = Self(<Self as Uint>::MIN);
/// The largest value that can be represented by this integer type.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// assert_eq!(u::<6>::MAX, 0);
/// ```
pub const MAX: Self = Self(<Self as Uint>::MAX);
/// The size of this integer type in bits.
///
/// # Examples
///
/// ```
/// assert_eq!(u::<6>::BITS, 6);
/// ```
pub const BITS: u32 = N as u32;
fn mask(self) -> Self {
Self(self.0 & Self::MAX.0)
}
pub fn new(v: <Self as Uint>::Inner) -> Self {
assert!(v <= Self::MAX.0, "value out of bounds");
Self(v)
}
pub fn wrapping_sub(self, rhs: Self) -> Self {
Self(self.0.wrapping_sub(rhs.0)).mask()
}
pub fn wrapping_add(self, rhs: Self) -> Self {
Self(self.0.wrapping_add(rhs.0)).mask()
}
}
impl<const N: usize> fmt::Display for u<N> where Self: Uint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Uint::Inner as fmt::Display>::fmt(&self.0, f)
}
}
impl<const N: usize> fmt::Debug for u<N> where Self: Uint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Uint::Inner as fmt::Debug>::fmt(&self.0, f)
}
}
impl<const N: usize> fmt::LowerHex for u<N> where Self: Uint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Uint::Inner as fmt::LowerHex>::fmt(&self.0, f)
}
}
impl<const N: usize> fmt::UpperHex for u<N> where Self: Uint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Uint::Inner as fmt::UpperHex>::fmt(&self.0, f)
}
}
impl<const N: usize> fmt::Octal for u<N> where Self: Uint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Uint::Inner as fmt::Octal>::fmt(&self.0, f)
}
}
impl<const N: usize> fmt::Binary for u<N> where Self: Uint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Uint::Inner as fmt::Binary>::fmt(&self.0, f)
}
}
impl<T, const N: usize> Shr<T> for u<N>
where
Self: Uint,
<Self as Uint>::Inner: Shr<T, Output=<Self as Uint>::Inner>,
{
type Output = Self;
fn shr(self, rhs: T) -> Self {
Self(self.0.shr(rhs))
}
}
impl<T, const N: usize> Shl<T> for u<N>
where
Self: Uint,
<Self as Uint>::Inner: Shl<T, Output=<Self as Uint>::Inner>,
{
type Output = Self;
fn shl(self, rhs: T) -> Self {
Self(self.0.shl(rhs)).mask()
}
}
impl<T, const N: usize> ShrAssign<T> for u<N>
where
Self: Uint,
<Self as Uint>::Inner: ShrAssign<T>,
{
fn shr_assign(&mut self, rhs: T) {
*self = *self >> rhs;
}
}
impl<T, const N: usize> ShlAssign<T> for u<N>
where
Self: Uint,
<Self as Uint>::Inner: ShlAssign<T>,
{
fn shl_assign(&mut self, rhs: T) {
*self = (*self << rhs).mask();
}
}
fn main() {
println!("{}", u::<6>::MAX);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment