#![no_std]
#[macro_export]
macro_rules! newtype {
($name:ident, $base:ident, $inner:ty) => {
pub type $name = $base<$inner>;
};
($name:ident, $inner:ty) => {
pub type $name = NewType<$inner>;
};
}
#[macro_export]
macro_rules! base_newtype {
() => {
$crate::base_newtype!(NewType);
};
($name:ident) => {
#[repr(transparent)]
pub struct $name<T>(pub T);
impl<T> $name<T> {
#[inline(always)]
pub const fn new(value: T) -> Self {
$name(value)
}
#[inline(always)]
pub const fn inner(&self) -> &T {
&self.0
}
#[inline(always)]
pub const fn inner_mut(&mut self) -> &mut T {
&mut self.0
}
#[inline(always)]
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> From<T> for $name<T> {
#[inline(always)]
fn from(value: T) -> Self {
$name(value)
}
}
impl<T> AsRef<T> for $name<T> {
#[inline(always)]
fn as_ref(&self) -> &T {
&self.0
}
}
impl<T> AsMut<T> for $name<T> {
#[inline(always)]
fn as_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T> core::ops::Deref for $name<T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> core::ops::DerefMut for $name<T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T: Default> Default for $name<T> {
#[inline(always)]
fn default() -> Self {
$name(T::default())
}
}
impl<T: Clone> Clone for $name<T> {
#[inline(always)]
fn clone(&self) -> Self {
$name(self.0.clone())
}
}
impl<T: Copy> Copy for $name<T> {}
impl<T: PartialEq> PartialEq for $name<T> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
impl<T: PartialEq> PartialEq<T> for $name<T> {
#[inline(always)]
fn eq(&self, other: &T) -> bool {
self.0.eq(other)
}
}
impl<T: Eq> Eq for $name<T> {}
impl<T: PartialOrd> PartialOrd for $name<T> {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
self.0.partial_cmp(&other.0)
}
}
impl<T: PartialOrd> PartialOrd<T> for $name<T> {
#[inline(always)]
fn partial_cmp(&self, other: &T) -> Option<core::cmp::Ordering> {
self.0.partial_cmp(other)
}
}
impl<T: Ord> Ord for $name<T> {
#[inline(always)]
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.0.cmp(&other.0)
}
}
impl<T: core::fmt::Debug> core::fmt::Debug for $name<T> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.0)
}
}
impl<T: core::fmt::Display> core::fmt::Display for $name<T> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.0)
}
}
impl<T: core::hash::Hash> core::hash::Hash for $name<T> {
#[inline(always)]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<T: core::iter::Iterator> core::iter::Iterator for $name<T> {
type Item = T::Item;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<T: core::iter::DoubleEndedIterator> core::iter::DoubleEndedIterator for $name<T> {
#[inline(always)]
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
impl<T: core::iter::ExactSizeIterator> core::iter::ExactSizeIterator for $name<T> {
#[inline(always)]
fn len(&self) -> usize {
self.0.len()
}
}
impl<T: core::iter::FusedIterator> core::iter::FusedIterator for $name<T> {}
impl<T: core::ops::Index<I>, I> core::ops::Index<I> for $name<T> {
type Output = T::Output;
#[inline(always)]
fn index(&self, index: I) -> &Self::Output {
&self.0[index]
}
}
impl<T: core::ops::IndexMut<I>, I> core::ops::IndexMut<I> for $name<T> {
#[inline(always)]
fn index_mut(&mut self, index: I) -> &mut Self::Output {
&mut self.0[index]
}
}
impl<T: core::ops::Add<T>> core::ops::Add<$name<T>> for $name<T> {
type Output = $name<<T as core::ops::Add<T>>::Output>;
#[inline(always)]
fn add(self, rhs: $name<T>) -> Self::Output {
$name(self.0 + rhs.0)
}
}
impl<T: core::ops::Add<T>> core::ops::Add<T> for $name<T> {
type Output = $name<<T as core::ops::Add<T>>::Output>;
#[inline(always)]
fn add(self, rhs: T) -> Self::Output {
$name(self.0 + rhs)
}
}
impl<T: core::ops::AddAssign<R>, R> core::ops::AddAssign<$name<R>> for $name<T> {
#[inline(always)]
fn add_assign(&mut self, rhs: $name<R>) {
self.0.add_assign(rhs.0);
}
}
impl<T: core::ops::Sub<T>> core::ops::Sub<$name<T>> for $name<T> {
type Output = $name<<T as core::ops::Sub<T>>::Output>;
#[inline(always)]
fn sub(self, rhs: $name<T>) -> Self::Output {
$name(self.0 - rhs.0)
}
}
impl<T: core::ops::Sub<T>> core::ops::Sub<T> for $name<T> {
type Output = $name<<T as core::ops::Sub<T>>::Output>;
#[inline(always)]
fn sub(self, rhs: T) -> Self::Output {
$name(self.0 - rhs)
}
}
impl<T: core::ops::SubAssign<R>, R> core::ops::SubAssign<$name<R>> for $name<T> {
#[inline(always)]
fn sub_assign(&mut self, rhs: $name<R>) {
self.0.sub_assign(rhs.0);
}
}
impl<T: core::ops::Mul<T>> core::ops::Mul<$name<T>> for $name<T> {
type Output = $name<<T as core::ops::Mul<T>>::Output>;
#[inline(always)]
fn mul(self, rhs: $name<T>) -> Self::Output {
$name(self.0 * rhs.0)
}
}
impl<T: core::ops::Mul<T>> core::ops::Mul<T> for $name<T> {
type Output = $name<<T as core::ops::Mul<T>>::Output>;
#[inline(always)]
fn mul(self, rhs: T) -> Self::Output {
$name(self.0 * rhs)
}
}
impl<T: core::ops::MulAssign<R>, R> core::ops::MulAssign<$name<R>> for $name<T> {
#[inline(always)]
fn mul_assign(&mut self, rhs: $name<R>) {
self.0.mul_assign(rhs.0);
}
}
impl<T: core::ops::Div<T>> core::ops::Div<$name<T>> for $name<T> {
type Output = $name<<T as core::ops::Div<T>>::Output>;
#[inline(always)]
fn div(self, rhs: $name<T>) -> Self::Output {
$name(self.0 / rhs.0)
}
}
impl<T: core::ops::Div<T>> core::ops::Div<T> for $name<T> {
type Output = $name<<T as core::ops::Div<T>>::Output>;
#[inline(always)]
fn div(self, rhs: T) -> Self::Output {
$name(self.0 / rhs)
}
}
impl<T: core::ops::DivAssign<R>, R> core::ops::DivAssign<$name<R>> for $name<T> {
#[inline(always)]
fn div_assign(&mut self, rhs: $name<R>) {
self.0.div_assign(rhs.0);
}
}
impl<T: core::ops::Rem<T>> core::ops::Rem<$name<T>> for $name<T> {
type Output = $name<<T as core::ops::Rem<T>>::Output>;
#[inline(always)]
fn rem(self, rhs: $name<T>) -> Self::Output {
$name(self.0 % rhs.0)
}
}
impl<T: core::ops::Rem<T>> core::ops::Rem<T> for $name<T> {
type Output = $name<<T as core::ops::Rem<T>>::Output>;
#[inline(always)]
fn rem(self, rhs: T) -> Self::Output {
$name(self.0 % rhs)
}
}
impl<T: core::ops::RemAssign<R>, R> core::ops::RemAssign<$name<R>> for $name<T> {
#[inline(always)]
fn rem_assign(&mut self, rhs: $name<R>) {
self.0.rem_assign(rhs.0);
}
}
impl<T: core::ops::Neg> core::ops::Neg for $name<T> {
type Output = $name<T::Output>;
#[inline(always)]
fn neg(self) -> Self::Output {
$name(-self.0)
}
}
impl<T: core::ops::Not> core::ops::Not for $name<T> {
type Output = $name<T::Output>;
#[inline(always)]
fn not(self) -> Self::Output {
$name(!self.0)
}
}
impl<T: core::ops::BitAnd<R>, R> core::ops::BitAnd<R> for $name<T> {
type Output = $name<<T as core::ops::BitAnd<R>>::Output>;
#[inline(always)]
fn bitand(self, rhs: R) -> Self::Output {
$name(self.0 & rhs)
}
}
impl<T: core::ops::BitAndAssign<R>, R> core::ops::BitAndAssign<R> for $name<T> {
#[inline(always)]
fn bitand_assign(&mut self, rhs: R) {
self.0.bitand_assign(rhs);
}
}
impl<T: core::ops::BitOr<R>, R> core::ops::BitOr<R> for $name<T> {
type Output = $name<<T as core::ops::BitOr<R>>::Output>;
#[inline(always)]
fn bitor(self, rhs: R) -> Self::Output {
$name(self.0 | rhs)
}
}
impl<T: core::ops::BitOrAssign<R>, R> core::ops::BitOrAssign<R> for $name<T> {
#[inline(always)]
fn bitor_assign(&mut self, rhs: R) {
self.0.bitor_assign(rhs);
}
}
impl<T: core::ops::BitXor<R>, R> core::ops::BitXor<R> for $name<T> {
type Output = $name<<T as core::ops::BitXor<R>>::Output>;
#[inline(always)]
fn bitxor(self, rhs: R) -> Self::Output {
$name(self.0 ^ rhs)
}
}
impl<T: core::ops::BitXorAssign<R>, R> core::ops::BitXorAssign<R> for $name<T> {
#[inline(always)]
fn bitxor_assign(&mut self, rhs: R) {
self.0.bitxor_assign(rhs);
}
}
impl<T: core::ops::Shl<R>, R> core::ops::Shl<R> for $name<T> {
type Output = $name<<T as core::ops::Shl<R>>::Output>;
#[inline(always)]
fn shl(self, rhs: R) -> Self::Output {
$name(self.0 << rhs)
}
}
impl<T: core::ops::ShlAssign<R>, R> core::ops::ShlAssign<R> for $name<T> {
#[inline(always)]
fn shl_assign(&mut self, rhs: R) {
self.0.shl_assign(rhs);
}
}
impl<T: core::ops::Shr<R>, R> core::ops::Shr<R> for $name<T> {
type Output = $name<<T as core::ops::Shr<R>>::Output>;
#[inline(always)]
fn shr(self, rhs: R) -> Self::Output {
$name(self.0 >> rhs)
}
}
impl<T: core::ops::ShrAssign<R>, R> core::ops::ShrAssign<R> for $name<T> {
#[inline(always)]
fn shr_assign(&mut self, rhs: R) {
self.0.shr_assign(rhs);
}
}
impl<T: core::ops::RangeBounds<R>, R> core::ops::RangeBounds<R> for $name<T> {
#[inline(always)]
fn start_bound(&self) -> core::ops::Bound<&R> {
self.0.start_bound()
}
#[inline(always)]
fn end_bound(&self) -> core::ops::Bound<&R> {
self.0.end_bound()
}
}
impl<T: core::str::FromStr> core::str::FromStr for $name<T> {
type Err = T::Err;
#[inline(always)]
fn from_str(s: &str) -> Result<Self, Self::Err> {
T::from_str(s).map($name)
}
}
impl<T> core::borrow::Borrow<T> for $name<T> {
#[inline(always)]
fn borrow(&self) -> &T {
&self.0
}
}
impl<T> core::borrow::BorrowMut<T> for $name<T> {
#[inline(always)]
fn borrow_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<U, T> core::iter::FromIterator<U> for $name<T>
where
T: core::iter::FromIterator<U>,
{
#[inline(always)]
fn from_iter<I: core::iter::IntoIterator<Item = U>>(iter: I) -> Self {
$name(T::from_iter(iter))
}
}
impl<U, T> core::iter::Extend<U> for $name<T>
where
T: core::iter::Extend<U>,
{
#[inline(always)]
fn extend<I: core::iter::IntoIterator<Item = U>>(&mut self, iter: I) {
self.0.extend(iter);
}
}
impl<T: core::fmt::Binary> core::fmt::Binary for $name<T> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Binary::fmt(&self.0, f)
}
}
impl<T: core::fmt::Octal> core::fmt::Octal for $name<T> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Octal::fmt(&self.0, f)
}
}
impl<T: core::fmt::LowerHex> core::fmt::LowerHex for $name<T> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::LowerHex::fmt(&self.0, f)
}
}
impl<T: core::fmt::UpperHex> core::fmt::UpperHex for $name<T> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::UpperHex::fmt(&self.0, f)
}
}
impl<T: core::fmt::LowerExp> core::fmt::LowerExp for $name<T> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::LowerExp::fmt(&self.0, f)
}
}
impl<T: core::fmt::UpperExp> core::fmt::UpperExp for $name<T> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::UpperExp::fmt(&self.0, f)
}
}
impl<T: core::fmt::Pointer> core::fmt::Pointer for $name<T> {
#[inline(always)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Pointer::fmt(&self.0, f)
}
}
};
}
#[allow(unused)]
mod tests {
use super::*;
extern crate alloc;
use alloc::format;
use alloc::vec;
use alloc::vec::Vec;
base_newtype!();
newtype!(WU32, NewType, u32);
newtype!(WI32, i32);
pub trait Foo<T> {
const DELTA: u8;
type Item;
fn fizz(&self) -> T;
fn set(&mut self, v: T);
fn into_inner(self) -> T;
}
pub struct Thing<T>(pub T);
impl<T: Copy + Ord> Foo<T> for Thing<T> {
const DELTA: u8 = 99;
type Item = T;
fn fizz(&self) -> T {
self.0
}
fn set(&mut self, v: T) {
self.0 = v;
}
fn into_inner(self) -> T {
self.0
}
}
#[derive(Default)]
struct SimpleHasher(u64);
impl core::hash::Hasher for SimpleHasher {
fn write(&mut self, bytes: &[u8]) {
for b in bytes {
self.0 = self.0.wrapping_add(*b as u64);
}
}
fn finish(&self) -> u64 {
self.0
}
}
#[test]
fn test_deref() {
let w: WU32 = WU32::new(42);
assert_eq!(*w, 42);
let mut w_mut: WU32 = WU32::new(100);
*w_mut = 200;
assert_eq!(*w_mut, 200);
let i: WI32 = WI32::new(10);
assert_eq!(*i, 10);
let mut i_mut: WI32 = WI32::new(20);
*i_mut = 30;
assert_eq!(*i_mut, 30);
}
#[test]
fn test_math_ops() {
let a: WU32 = WU32::new(10);
let b: WU32 = WU32::new(5);
let sum: WU32 = a + b;
assert_eq!(*sum, 15);
let sum = a + 5;
assert_eq!(*sum, 15);
let diff = a - b;
assert_eq!(*diff, 5);
let diff = a - 5;
assert_eq!(*diff, 5);
let prod = a * b;
assert_eq!(*prod, 50);
let prod = a * 5;
assert_eq!(*prod, 50);
let quot = a / b;
assert_eq!(*quot, 2);
let quot = a / 5;
assert_eq!(*quot, 2);
let rem = a % b;
assert_eq!(*rem, 0);
let rem = a % 5;
assert_eq!(*rem, 0);
let c = WI32::new(10);
let neg_c = -c;
assert_eq!(*neg_c, -10);
}
#[test]
fn test_math_ops_assign() {
let mut x: WU32 = WU32::new(10);
x += WU32::new(2);
assert_eq!(*x, 12);
x -= WU32::new(5);
assert_eq!(*x, 7);
x *= WU32::new(3);
assert_eq!(*x, 21);
x /= WU32::new(7);
assert_eq!(*x, 3);
x %= WU32::new(2);
assert_eq!(*x, 1);
}
#[test]
fn test_bool() {
newtype!(BetterBool, bool);
let a: BetterBool = BetterBool::new(true);
let b: BetterBool = BetterBool::new(false);
assert_eq!(a, true);
assert_ne!(a, false);
assert_ne!(a, b)
}
#[test]
fn test_default_clone_asref() {
let mut x: WU32 = Default::default();
assert_eq!(x, 0);
let y = x;
assert_eq!(x, y);
*x.as_mut() = 5;
assert_eq!(x.as_ref(), &5);
}
#[test]
fn test_from_str() {
newtype!(Num, u32);
let n: Num = "42".parse().unwrap();
assert_eq!(n, 42);
}
#[test]
fn test_iterator() {
newtype!(R, core::ops::Range<u8>);
let mut r = R::new(1..4);
assert_eq!(r.len(), 3);
assert_eq!(r.next(), Some(1));
assert_eq!(r.next_back(), Some(3));
assert_eq!(r.next(), Some(2));
assert_eq!(r.next(), None);
}
#[test]
fn test_iterator_methods() {
newtype!(R, core::ops::Range<u8>);
let mut r = R::new(0..5);
assert_eq!(r.nth(2), Some(2));
assert_eq!(r.next_back(), Some(4));
let mut fused = R::new(0..2);
assert_eq!(fused.next(), Some(0));
assert_eq!(fused.next(), Some(1));
assert_eq!(fused.next(), None);
assert_eq!(fused.next(), None);
let collected: Vec<u8> = R::new(3..6).collect();
assert_eq!(collected, vec![3, 4, 5]);
}
#[test]
fn test_inner_and_from() {
let mut x: WU32 = 5u32.into();
assert_eq!(*x.inner(), 5);
*x.inner_mut() = 7;
assert_eq!(x.into_inner(), 7);
}
#[test]
fn test_display_debug_hash() {
use core::hash::{Hash, Hasher};
let x: WU32 = 42u32.into();
assert_eq!(format!("{x}"), "42");
assert_eq!(format!("{x:?}"), "42");
let mut hx = SimpleHasher::default();
x.hash(&mut hx);
let mut hy = SimpleHasher::default();
42u32.hash(&mut hy);
assert_eq!(hx.finish(), hy.finish());
}
#[test]
fn test_ordering() {
let a = WU32::new(1);
let b = WU32::new(2);
assert!(a < b);
assert!(b > a);
assert!(b > 1);
let mut v = vec![b, a];
v.sort();
assert_eq!(v, vec![a, b]);
}
#[test]
fn test_indexing() {
newtype!(WVec, Vec<u8>);
let mut w = WVec::new(vec![1, 2, 3]);
assert_eq!(w[1], 2);
w[1] = 4;
assert_eq!(w[1], 4);
}
#[test]
fn test_bit_ops() {
let mut x = WU32::new(0b1010u32);
assert_eq!(*(x & 0b1100u32).inner(), 0b1000u32);
x &= 0b1100u32;
assert_eq!(x, 0b1000u32);
assert_eq!(*(x | 0b0011u32).inner(), 0b1011u32);
x |= 0b0011u32;
assert_eq!(x, 0b1011u32);
assert_eq!(*(x ^ 0b1111u32).inner(), 0b0100u32);
x ^= 0b1111u32;
assert_eq!(x, 0b0100u32);
assert_eq!((!x).into_inner(), !0b0100u32);
let shifted: WU32 = x << 2;
assert_eq!(shifted.into_inner(), 0b0100u32 << 2);
x <<= 1;
assert_eq!(x.into_inner(), 0b0100u32 << 1);
let mut y = WU32::new(0b1000u32);
let shr: WU32 = y >> 2;
assert_eq!(shr.into_inner(), 0b1000u32 >> 2);
y >>= 1;
assert_eq!(y.into_inner(), 0b1000u32 >> 1);
}
#[test]
fn test_range_bounds() {
use core::ops::{Bound, RangeBounds};
newtype!(R, core::ops::Range<u8>);
let r = R::new(1..4);
assert_eq!(RangeBounds::start_bound(&r), Bound::Included(&1));
assert_eq!(RangeBounds::end_bound(&r), Bound::Excluded(&4));
}
#[test]
fn test_borrow_traits() {
use core::borrow::{Borrow, BorrowMut};
let mut x = WU32::new(5);
let r: &u32 = x.borrow();
assert_eq!(*r, 5);
*x.borrow_mut() = 7;
assert_eq!(x, 7u32);
}
#[test]
fn test_formatting_traits() {
let x = WU32::new(42);
assert_eq!(format!("{x:b}"), format!("{:b}", 42u32));
assert_eq!(format!("{x:o}"), format!("{:o}", 42u32));
assert_eq!(format!("{x:x}"), format!("{:x}", 42u32));
}
}