#[doc(hidden)]
#[macro_export]
macro_rules! _nt_base {
($name:ident, $inner:ty) => {
#[repr(transparent)]
#[derive(Debug)]
pub struct $name($inner);
impl From<$name> for $inner {
fn from(value: $name) -> $inner {
value.0
}
}
};
($name:ident, $inner:ty; $($derive:path),+) => {
#[repr(transparent)]
#[derive(Debug, $($derive),+)]
pub struct $name($inner);
impl From<$name> for $inner {
fn from(value: $name) -> $inner {
value.0
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_clone_traits {
($name:ident) => {
impl Clone for $name {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_copy_traits {
($name:ident) => {
impl Clone for $name {
fn clone(&self) -> Self {
*self
}
}
impl Copy for $name {}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_partialeq_traits {
($name:ident) => {
impl PartialEq for $name {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_eq_traits {
($name:ident) => {
$crate::_nt_partialeq_traits!($name);
impl Eq for $name {}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_partialord_traits {
($name:ident) => {
impl PartialOrd for $name {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.0.partial_cmp(&other.0)
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_ord_traits {
($name:ident) => {
impl Ord for $name {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.cmp(&other.0)
}
}
impl PartialOrd for $name {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_hash_traits {
($name:ident) => {
impl std::hash::Hash for $name {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_addsub_traits {
($name:ident) => {
impl Default for $name {
fn default() -> Self {
Self(Default::default())
}
}
impl std::ops::Add<$name> for $name {
type Output = $name;
fn add(self, rhs: Self) -> Self::Output {
$name(self.0 + rhs.0)
}
}
impl std::ops::Add<&$name> for $name {
type Output = $name;
fn add(self, rhs: &$name) -> Self::Output {
$name(self.0 + rhs.0)
}
}
impl std::ops::Add<$name> for &$name {
type Output = $name;
fn add(self, rhs: $name) -> Self::Output {
$name(self.0 + rhs.0)
}
}
impl std::ops::Add<&$name> for &$name {
type Output = $name;
fn add(self, rhs: &$name) -> Self::Output {
$name(self.0 + rhs.0)
}
}
impl std::ops::Sub<$name> for $name {
type Output = $name;
fn sub(self, rhs: Self) -> Self::Output {
$name(self.0 - rhs.0)
}
}
impl std::ops::Sub<&$name> for $name {
type Output = $name;
fn sub(self, rhs: &$name) -> Self::Output {
$name(self.0 - rhs.0)
}
}
impl std::ops::Sub<$name> for &$name {
type Output = $name;
fn sub(self, rhs: $name) -> Self::Output {
$name(self.0 - rhs.0)
}
}
impl std::ops::Sub<&$name> for &$name {
type Output = $name;
fn sub(self, rhs: &$name) -> Self::Output {
$name(self.0 - rhs.0)
}
}
impl std::ops::AddAssign<$name> for $name {
fn add_assign(&mut self, rhs: $name) {
self.0 += rhs.0;
}
}
impl std::ops::AddAssign<&$name> for $name {
fn add_assign(&mut self, rhs: &$name) {
self.0 += rhs.0;
}
}
impl std::ops::SubAssign<$name> for $name {
fn sub_assign(&mut self, rhs: $name) {
self.0 -= rhs.0;
}
}
impl std::ops::SubAssign<&$name> for $name {
fn sub_assign(&mut self, rhs: &$name) {
self.0 -= rhs.0;
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_clone {
($name:ident, $inner:ty) => {
$crate::_nt_base!($name, $inner);
$crate::_nt_clone_traits!($name);
};
($name:ident, $inner:ty; $($derive:path),+) => {
$crate::_nt_base!($name, $inner; $($derive),+);
$crate::_nt_clone_traits!($name);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_copy {
($name:ident, $inner:ty) => {
$crate::_nt_base!($name, $inner);
$crate::_nt_copy_traits!($name);
};
($name:ident, $inner:ty; $($derive:path),+) => {
$crate::_nt_base!($name, $inner; $($derive),+);
$crate::_nt_copy_traits!($name);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_int {
($name:ident, $inner:ty) => {
$crate::_nt_copy!($name, $inner);
$crate::_nt_eq_traits!($name);
$crate::_nt_hash_traits!($name);
};
($name:ident, $inner:ty; $($derive:path),+) => {
$crate::_nt_copy!($name, $inner; $($derive),+);
$crate::_nt_eq_traits!($name);
$crate::_nt_hash_traits!($name);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_float {
($name:ident, $inner:ty) => {
$crate::_nt_copy!($name, $inner);
$crate::_nt_partialeq_traits!($name);
};
($name:ident, $inner:ty; $($derive:path),+) => {
$crate::_nt_copy!($name, $inner; $($derive),+);
$crate::_nt_partialeq_traits!($name);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_string {
($name:ident) => {
$crate::_nt_clone!($name, String);
$crate::_nt_eq_traits!($name);
$crate::_nt_hash_traits!($name);
};
($name:ident; $($derive:path),+) => {
$crate::_nt_clone!($name, String; $($derive),+);
$crate::_nt_eq_traits!($name);
$crate::_nt_hash_traits!($name);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_int_ord {
($name:ident, $inner:ty) => {
$crate::_nt_int!($name, $inner);
$crate::_nt_ord_traits!($name);
};
($name:ident, $inner:ty; $($derive:path),+) => {
$crate::_nt_int!($name, $inner; $($derive),+);
$crate::_nt_ord_traits!($name);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_float_ord {
($name:ident, $inner:ty) => {
$crate::_nt_float!($name, $inner);
$crate::_nt_partialord_traits!($name);
};
($name:ident, $inner:ty; $($derive:path),+) => {
$crate::_nt_float!($name, $inner; $($derive),+);
$crate::_nt_partialord_traits!($name);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_string_ord {
($name:ident) => {
$crate::_nt_string!($name);
$crate::_nt_ord_traits!($name);
};
($name:ident; $($derive:path),+) => {
$crate::_nt_string!($name; $($derive),+);
$crate::_nt_ord_traits!($name);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_int_unit {
($name:ident, $inner:ty) => {
$crate::_nt_int_ord!($name, $inner);
$crate::_nt_addsub_traits!($name);
};
($name:ident, $inner:ty; $($derive:path),+) => {
$crate::_nt_int_ord!($name, $inner; $($derive),+);
$crate::_nt_addsub_traits!($name);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_float_unit {
($name:ident, $inner:ty) => {
$crate::_nt_float_ord!($name, $inner);
$crate::_nt_addsub_traits!($name);
};
($name:ident, $inner:ty; $($derive:path),+) => {
$crate::_nt_float_ord!($name, $inner; $($derive),+);
$crate::_nt_addsub_traits!($name);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_from_traits {
($name:ident, $inner:ty) => {
impl From<$inner> for $name {
#[inline(always)]
fn from(value: $inner) -> Self {
$name(value)
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_fromstr_traits {
($name:ident, $inner:ty, $err:ty) => {
impl std::str::FromStr for $name {
type Err = $err;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match <$inner>::from_str(s) {
Ok(v) => Ok($name(v)),
Err(e) => Err(e),
}
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_int_from {
($name:ident, $inner:ty) => {
$crate::_nt_from_traits!($name, $inner);
$crate::_nt_fromstr_traits!($name, $inner, std::num::ParseIntError);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_float_from {
($name:ident, $inner:ty) => {
$crate::_nt_from_traits!($name, $inner);
$crate::_nt_fromstr_traits!($name, $inner, std::num::ParseFloatError);
};
}
#[macro_export]
macro_rules! newtype {
($name:ident, i8) => { $crate::_nt_int!($name, i8); };
($name:ident, u8) => { $crate::_nt_int!($name, u8); };
($name:ident, i16) => { $crate::_nt_int!($name, i16); };
($name:ident, u16) => { $crate::_nt_int!($name, u16); };
($name:ident, i32) => { $crate::_nt_int!($name, i32); };
($name:ident, u32) => { $crate::_nt_int!($name, u32); };
($name:ident, i64) => { $crate::_nt_int!($name, i64); };
($name:ident, u64) => { $crate::_nt_int!($name, u64); };
($name:ident, i128) => { $crate::_nt_int!($name, i128); };
($name:ident, u128) => { $crate::_nt_int!($name, u128); };
($name:ident, isize) => { $crate::_nt_int!($name, isize); };
($name:ident, usize) => { $crate::_nt_int!($name, usize); };
($name:ident, i8; $($derive:path),+) => { $crate::_nt_int!($name, i8; $($derive),+); };
($name:ident, u8; $($derive:path),+) => { $crate::_nt_int!($name, u8; $($derive),+); };
($name:ident, i16; $($derive:path),+) => { $crate::_nt_int!($name, i16; $($derive),+); };
($name:ident, u16; $($derive:path),+) => { $crate::_nt_int!($name, u16; $($derive),+); };
($name:ident, i32; $($derive:path),+) => { $crate::_nt_int!($name, i32; $($derive),+); };
($name:ident, u32; $($derive:path),+) => { $crate::_nt_int!($name, u32; $($derive),+); };
($name:ident, i64; $($derive:path),+) => { $crate::_nt_int!($name, i64; $($derive),+); };
($name:ident, u64; $($derive:path),+) => { $crate::_nt_int!($name, u64; $($derive),+); };
($name:ident, i128; $($derive:path),+) => { $crate::_nt_int!($name, i128; $($derive),+); };
($name:ident, u128; $($derive:path),+) => { $crate::_nt_int!($name, u128; $($derive),+); };
($name:ident, isize; $($derive:path),+) => { $crate::_nt_int!($name, isize; $($derive),+); };
($name:ident, usize; $($derive:path),+) => { $crate::_nt_int!($name, usize; $($derive),+); };
($name:ident, f32) => { $crate::_nt_float!($name, f32); };
($name:ident, f64) => { $crate::_nt_float!($name, f64); };
($name:ident, f32; $($derive:path),+) => { $crate::_nt_float!($name, f32; $($derive),+); };
($name:ident, f64; $($derive:path),+) => { $crate::_nt_float!($name, f64; $($derive),+); };
($name:ident, String) => { $crate::_nt_string!($name); };
($name:ident, String; $($derive:path),+) => { $crate::_nt_string!($name; $($derive),+); };
($name:ident, $inner:ty) => {
$crate::_nt_base!($name, $inner);
};
($name:ident, $inner:ty; $($derive:path),+) => {
$crate::_nt_base!($name, $inner; $($derive),+);
}
}
#[macro_export]
macro_rules! newtype_ord {
($name:ident, i8) => { $crate::_nt_int_ord!($name, i8); };
($name:ident, u8) => { $crate::_nt_int_ord!($name, u8); };
($name:ident, i16) => { $crate::_nt_int_ord!($name, i16); };
($name:ident, u16) => { $crate::_nt_int_ord!($name, u16); };
($name:ident, i32) => { $crate::_nt_int_ord!($name, i32); };
($name:ident, u32) => { $crate::_nt_int_ord!($name, u32); };
($name:ident, i64) => { $crate::_nt_int_ord!($name, i64); };
($name:ident, u64) => { $crate::_nt_int_ord!($name, u64); };
($name:ident, i128) => { $crate::_nt_int_ord!($name, i128); };
($name:ident, u128) => { $crate::_nt_int_ord!($name, u128); };
($name:ident, isize) => { $crate::_nt_int_ord!($name, isize); };
($name:ident, usize) => { $crate::_nt_int_ord!($name, usize); };
($name:ident, i8; $($derive:path),+) => { $crate::_nt_int_ord!($name, i8; $($derive),+); };
($name:ident, u8; $($derive:path),+) => { $crate::_nt_int_ord!($name, u8; $($derive),+); };
($name:ident, i16; $($derive:path),+) => { $crate::_nt_int_ord!($name, i16; $($derive),+); };
($name:ident, u16; $($derive:path),+) => { $crate::_nt_int_ord!($name, u16; $($derive),+); };
($name:ident, i32; $($derive:path),+) => { $crate::_nt_int_ord!($name, i32; $($derive),+); };
($name:ident, u32; $($derive:path),+) => { $crate::_nt_int_ord!($name, u32; $($derive),+); };
($name:ident, i64; $($derive:path),+) => { $crate::_nt_int_ord!($name, i64; $($derive),+); };
($name:ident, u64; $($derive:path),+) => { $crate::_nt_int_ord!($name, u64; $($derive),+); };
($name:ident, i128; $($derive:path),+) => { $crate::_nt_int_ord!($name, i128; $($derive),+); };
($name:ident, u128; $($derive:path),+) => { $crate::_nt_int_ord!($name, u128; $($derive),+); };
($name:ident, isize; $($derive:path),+) => { $crate::_nt_int_ord!($name, isize; $($derive),+); };
($name:ident, usize; $($derive:path),+) => { $crate::_nt_int_ord!($name, usize; $($derive),+); };
($name:ident, f32) => { $crate::_nt_float_ord!($name, f32); };
($name:ident, f64) => { $crate::_nt_float_ord!($name, f64); };
($name:ident, f32; $($derive:path),+) => { $crate::_nt_float_ord!($name, f32; $($derive),+); };
($name:ident, f64; $($derive:path),+) => { $crate::_nt_float_ord!($name, f64; $($derive),+); };
($name:ident, String) => { $crate::_nt_string_ord!($name); };
($name:ident, String; $($derive:path),+) => { $crate::_nt_string_ord!($name; $($derive),+); };
}
#[macro_export]
macro_rules! newtype_unit {
($name:ident, i8) => { $crate::_nt_int_unit!($name, i8); };
($name:ident, u8) => { $crate::_nt_int_unit!($name, u8); };
($name:ident, i16) => { $crate::_nt_int_unit!($name, i16); };
($name:ident, u16) => { $crate::_nt_int_unit!($name, u16); };
($name:ident, i32) => { $crate::_nt_int_unit!($name, i32); };
($name:ident, u32) => { $crate::_nt_int_unit!($name, u32); };
($name:ident, i64) => { $crate::_nt_int_unit!($name, i64); };
($name:ident, u64) => { $crate::_nt_int_unit!($name, u64); };
($name:ident, i128) => { $crate::_nt_int_unit!($name, i128); };
($name:ident, u128) => { $crate::_nt_int_unit!($name, u128); };
($name:ident, isize) => { $crate::_nt_int_unit!($name, isize); };
($name:ident, usize) => { $crate::_nt_int_unit!($name, usize); };
($name:ident, i8; $($derive:path),+) => { $crate::_nt_int_unit!($name, i8; $($derive),+); };
($name:ident, u8; $($derive:path),+) => { $crate::_nt_int_unit!($name, u8; $($derive),+); };
($name:ident, i16; $($derive:path),+) => { $crate::_nt_int_unit!($name, i16; $($derive),+); };
($name:ident, u16; $($derive:path),+) => { $crate::_nt_int_unit!($name, u16; $($derive),+); };
($name:ident, i32; $($derive:path),+) => { $crate::_nt_int_unit!($name, i32; $($derive),+); };
($name:ident, u32; $($derive:path),+) => { $crate::_nt_int_unit!($name, u32; $($derive),+); };
($name:ident, i64; $($derive:path),+) => { $crate::_nt_int_unit!($name, i64; $($derive),+); };
($name:ident, u64; $($derive:path),+) => { $crate::_nt_int_unit!($name, u64; $($derive),+); };
($name:ident, i128; $($derive:path),+) => { $crate::_nt_int_unit!($name, i128; $($derive),+); };
($name:ident, u128; $($derive:path),+) => { $crate::_nt_int_unit!($name, u128; $($derive),+); };
($name:ident, isize; $($derive:path),+) => { $crate::_nt_int_unit!($name, isize; $($derive),+); };
($name:ident, usize; $($derive:path),+) => { $crate::_nt_int_unit!($name, usize; $($derive),+); };
($name:ident, f32) => { $crate::_nt_float_unit!($name, f32); };
($name:ident, f64) => { $crate::_nt_float_unit!($name, f64); };
($name:ident, f32; $($derive:path),+) => { $crate::_nt_float_unit!($name, f32; $($derive),+); };
($name:ident, f64; $($derive:path),+) => { $crate::_nt_float_unit!($name, f64; $($derive),+); };
}
#[macro_export]
macro_rules! newtype_struct {
($name:ident, $inner:ty) => {
$crate::_nt_base!($name, $inner);
$crate::_nt_clone_traits!($name);
$crate::_nt_partialeq_traits!($name);
};
($name:ident, $inner:ty; $($derive:path),+) => {
$crate::_nt_base!($name, $inner; $($derive),+);
$crate::_nt_clone_traits!($name);
$crate::_nt_partialeq_traits!($name);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_validated_impls {
($name:ident, $err:ident, $inner:ty, $validator:expr) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct $err;
impl ::std::fmt::Display for $err {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
write!(f, concat!("invalid ", stringify!($name), " value"))
}
}
impl ::std::error::Error for $err {}
impl $name {
pub fn new(value: $inner) -> ::std::result::Result<Self, $err> {
if ($validator)(&value) {
Ok($name(value))
} else {
Err($err)
}
}
}
impl ::std::convert::TryFrom<$inner> for $name {
type Error = $err;
fn try_from(value: $inner) -> ::std::result::Result<Self, Self::Error> {
Self::new(value)
}
}
};
}
#[macro_export]
macro_rules! newtype_validated {
($name:ident, $err:ident, $inner:ty, $validator:expr) => {
$crate::_nt_base!($name, $inner);
$crate::_nt_clone_traits!($name);
$crate::_nt_partialeq_traits!($name);
$crate::_nt_validated_impls!($name, $err, $inner, $validator);
};
($name:ident, $err:ident, $inner:ty, $validator:expr; $($derive:path),+) => {
$crate::_nt_base!($name, $inner; $($derive),+);
$crate::_nt_clone_traits!($name);
$crate::_nt_partialeq_traits!($name);
$crate::_nt_validated_impls!($name, $err, $inner, $validator);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_array_base {
($name:ident, $t:ty, $n:expr) => {
#[repr(transparent)]
#[derive(Debug)]
pub struct $name([$t; $n]);
impl From<$name> for [$t; $n] {
fn from(value: $name) -> [$t; $n] {
value.0
}
}
};
($name:ident, $t:ty, $n:expr; $($derive:path),+) => {
#[repr(transparent)]
#[derive(Debug, $($derive),+)]
pub struct $name([$t; $n]);
impl From<$name> for [$t; $n] {
fn from(value: $name) -> [$t; $n] {
value.0
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_array_ops {
($name:ident, $t:ty, $n:expr) => {
impl<I: std::slice::SliceIndex<[$t]>> std::ops::Index<I> for $name {
type Output = I::Output;
#[inline]
fn index(&self, index: I) -> &Self::Output {
std::ops::Index::index(&self.0[..], index)
}
}
impl<I: std::slice::SliceIndex<[$t]>> std::ops::IndexMut<I> for $name {
#[inline]
fn index_mut(&mut self, index: I) -> &mut Self::Output {
std::ops::IndexMut::index_mut(&mut self.0[..], index)
}
}
impl AsRef<[$t]> for $name {
#[inline]
fn as_ref(&self) -> &[$t] {
&self.0[..]
}
}
impl AsMut<[$t]> for $name {
#[inline]
fn as_mut(&mut self) -> &mut [$t] {
&mut self.0[..]
}
}
impl<'a> IntoIterator for &'a $name {
type Item = &'a $t;
type IntoIter = std::slice::Iter<'a, $t>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a> IntoIterator for &'a mut $name {
type Item = &'a mut $t;
type IntoIter = std::slice::IterMut<'a, $t>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
impl IntoIterator for $name {
type Item = $t;
type IntoIter = std::array::IntoIter<$t, $n>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl $name {
#[inline]
pub const fn len(&self) -> usize {
$n
}
#[inline]
pub const fn is_empty(&self) -> bool {
$n == 0
}
#[inline]
pub fn iter(&self) -> std::slice::Iter<'_, $t> {
self.0.iter()
}
#[inline]
pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, $t> {
self.0.iter_mut()
}
#[inline]
pub const fn as_array(&self) -> &[$t; $n] {
&self.0
}
#[inline]
pub const fn as_array_mut(&mut self) -> &mut [$t; $n] {
&mut self.0
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_array_deref_impls {
($name:ident, $t:ty) => {
impl std::ops::Deref for $name {
type Target = [$t];
#[inline]
fn deref(&self) -> &[$t] {
&self.0[..]
}
}
impl std::ops::DerefMut for $name {
#[inline]
fn deref_mut(&mut self) -> &mut [$t] {
&mut self.0[..]
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_array_int {
($name:ident, $t:ty, $n:expr) => {
$crate::_nt_array_base!($name, $t, $n);
$crate::_nt_copy_traits!($name);
$crate::_nt_eq_traits!($name);
$crate::_nt_hash_traits!($name);
$crate::_nt_array_ops!($name, $t, $n);
};
($name:ident, $t:ty, $n:expr; $($derive:path),+) => {
$crate::_nt_array_base!($name, $t, $n; $($derive),+);
$crate::_nt_copy_traits!($name);
$crate::_nt_eq_traits!($name);
$crate::_nt_hash_traits!($name);
$crate::_nt_array_ops!($name, $t, $n);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_array_float {
($name:ident, $t:ty, $n:expr) => {
$crate::_nt_array_base!($name, $t, $n);
$crate::_nt_copy_traits!($name);
$crate::_nt_partialeq_traits!($name);
$crate::_nt_array_ops!($name, $t, $n);
};
($name:ident, $t:ty, $n:expr; $($derive:path),+) => {
$crate::_nt_array_base!($name, $t, $n; $($derive),+);
$crate::_nt_copy_traits!($name);
$crate::_nt_partialeq_traits!($name);
$crate::_nt_array_ops!($name, $t, $n);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_array_string {
($name:ident, $n:expr) => {
$crate::_nt_array_base!($name, String, $n);
$crate::_nt_clone_traits!($name);
$crate::_nt_eq_traits!($name);
$crate::_nt_hash_traits!($name);
$crate::_nt_array_ops!($name, String, $n);
};
($name:ident, $n:expr; $($derive:path),+) => {
$crate::_nt_array_base!($name, String, $n; $($derive),+);
$crate::_nt_clone_traits!($name);
$crate::_nt_eq_traits!($name);
$crate::_nt_hash_traits!($name);
$crate::_nt_array_ops!($name, String, $n);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! _nt_array_generic {
($name:ident, $t:ty, $n:expr) => {
$crate::_nt_array_base!($name, $t, $n);
$crate::_nt_clone_traits!($name);
$crate::_nt_partialeq_traits!($name);
$crate::_nt_array_ops!($name, $t, $n);
};
($name:ident, $t:ty, $n:expr; $($derive:path),+) => {
$crate::_nt_array_base!($name, $t, $n; $($derive),+);
$crate::_nt_clone_traits!($name);
$crate::_nt_partialeq_traits!($name);
$crate::_nt_array_ops!($name, $t, $n);
};
}
#[macro_export]
macro_rules! newtype_array {
($name:ident, i8, $n:expr) => { $crate::_nt_array_int!($name, i8, $n); };
($name:ident, u8, $n:expr) => { $crate::_nt_array_int!($name, u8, $n); };
($name:ident, i16, $n:expr) => { $crate::_nt_array_int!($name, i16, $n); };
($name:ident, u16, $n:expr) => { $crate::_nt_array_int!($name, u16, $n); };
($name:ident, i32, $n:expr) => { $crate::_nt_array_int!($name, i32, $n); };
($name:ident, u32, $n:expr) => { $crate::_nt_array_int!($name, u32, $n); };
($name:ident, i64, $n:expr) => { $crate::_nt_array_int!($name, i64, $n); };
($name:ident, u64, $n:expr) => { $crate::_nt_array_int!($name, u64, $n); };
($name:ident, i128, $n:expr) => { $crate::_nt_array_int!($name, i128, $n); };
($name:ident, u128, $n:expr) => { $crate::_nt_array_int!($name, u128, $n); };
($name:ident, isize, $n:expr) => { $crate::_nt_array_int!($name, isize, $n); };
($name:ident, usize, $n:expr) => { $crate::_nt_array_int!($name, usize, $n); };
($name:ident, i8, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, i8, $n; $($derive),+); };
($name:ident, u8, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, u8, $n; $($derive),+); };
($name:ident, i16, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, i16, $n; $($derive),+); };
($name:ident, u16, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, u16, $n; $($derive),+); };
($name:ident, i32, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, i32, $n; $($derive),+); };
($name:ident, u32, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, u32, $n; $($derive),+); };
($name:ident, i64, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, i64, $n; $($derive),+); };
($name:ident, u64, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, u64, $n; $($derive),+); };
($name:ident, i128, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, i128, $n; $($derive),+); };
($name:ident, u128, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, u128, $n; $($derive),+); };
($name:ident, isize, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, isize, $n; $($derive),+); };
($name:ident, usize, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, usize, $n; $($derive),+); };
($name:ident, f32, $n:expr) => { $crate::_nt_array_float!($name, f32, $n); };
($name:ident, f64, $n:expr) => { $crate::_nt_array_float!($name, f64, $n); };
($name:ident, f32, $n:expr; $($derive:path),+) => { $crate::_nt_array_float!($name, f32, $n; $($derive),+); };
($name:ident, f64, $n:expr; $($derive:path),+) => { $crate::_nt_array_float!($name, f64, $n; $($derive),+); };
($name:ident, String, $n:expr) => { $crate::_nt_array_string!($name, $n); };
($name:ident, String, $n:expr; $($derive:path),+) => { $crate::_nt_array_string!($name, $n; $($derive),+); };
($name:ident, $t:ty, $n:expr) => { $crate::_nt_array_generic!($name, $t, $n); };
($name:ident, $t:ty, $n:expr; $($derive:path),+) => { $crate::_nt_array_generic!($name, $t, $n; $($derive),+); };
}
#[macro_export]
macro_rules! newtype_array_deref {
($name:ident, i8, $n:expr) => { $crate::_nt_array_int!($name, i8, $n); $crate::_nt_array_deref_impls!($name, i8); };
($name:ident, u8, $n:expr) => { $crate::_nt_array_int!($name, u8, $n); $crate::_nt_array_deref_impls!($name, u8); };
($name:ident, i16, $n:expr) => { $crate::_nt_array_int!($name, i16, $n); $crate::_nt_array_deref_impls!($name, i16); };
($name:ident, u16, $n:expr) => { $crate::_nt_array_int!($name, u16, $n); $crate::_nt_array_deref_impls!($name, u16); };
($name:ident, i32, $n:expr) => { $crate::_nt_array_int!($name, i32, $n); $crate::_nt_array_deref_impls!($name, i32); };
($name:ident, u32, $n:expr) => { $crate::_nt_array_int!($name, u32, $n); $crate::_nt_array_deref_impls!($name, u32); };
($name:ident, i64, $n:expr) => { $crate::_nt_array_int!($name, i64, $n); $crate::_nt_array_deref_impls!($name, i64); };
($name:ident, u64, $n:expr) => { $crate::_nt_array_int!($name, u64, $n); $crate::_nt_array_deref_impls!($name, u64); };
($name:ident, i128, $n:expr) => { $crate::_nt_array_int!($name, i128, $n); $crate::_nt_array_deref_impls!($name, i128); };
($name:ident, u128, $n:expr) => { $crate::_nt_array_int!($name, u128, $n); $crate::_nt_array_deref_impls!($name, u128); };
($name:ident, isize, $n:expr) => { $crate::_nt_array_int!($name, isize, $n); $crate::_nt_array_deref_impls!($name, isize); };
($name:ident, usize, $n:expr) => { $crate::_nt_array_int!($name, usize, $n); $crate::_nt_array_deref_impls!($name, usize); };
($name:ident, i8, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, i8, $n; $($derive),+); $crate::_nt_array_deref_impls!($name, i8); };
($name:ident, u8, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, u8, $n; $($derive),+); $crate::_nt_array_deref_impls!($name, u8); };
($name:ident, i16, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, i16, $n; $($derive),+); $crate::_nt_array_deref_impls!($name, i16); };
($name:ident, u16, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, u16, $n; $($derive),+); $crate::_nt_array_deref_impls!($name, u16); };
($name:ident, i32, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, i32, $n; $($derive),+); $crate::_nt_array_deref_impls!($name, i32); };
($name:ident, u32, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, u32, $n; $($derive),+); $crate::_nt_array_deref_impls!($name, u32); };
($name:ident, i64, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, i64, $n; $($derive),+); $crate::_nt_array_deref_impls!($name, i64); };
($name:ident, u64, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, u64, $n; $($derive),+); $crate::_nt_array_deref_impls!($name, u64); };
($name:ident, i128, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, i128, $n; $($derive),+); $crate::_nt_array_deref_impls!($name, i128); };
($name:ident, u128, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, u128, $n; $($derive),+); $crate::_nt_array_deref_impls!($name, u128); };
($name:ident, isize, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, isize, $n; $($derive),+); $crate::_nt_array_deref_impls!($name, isize); };
($name:ident, usize, $n:expr; $($derive:path),+) => { $crate::_nt_array_int!($name, usize, $n; $($derive),+); $crate::_nt_array_deref_impls!($name, usize); };
($name:ident, f32, $n:expr) => { $crate::_nt_array_float!($name, f32, $n); $crate::_nt_array_deref_impls!($name, f32); };
($name:ident, f64, $n:expr) => { $crate::_nt_array_float!($name, f64, $n); $crate::_nt_array_deref_impls!($name, f64); };
($name:ident, f32, $n:expr; $($derive:path),+) => { $crate::_nt_array_float!($name, f32, $n; $($derive),+); $crate::_nt_array_deref_impls!($name, f32); };
($name:ident, f64, $n:expr; $($derive:path),+) => { $crate::_nt_array_float!($name, f64, $n; $($derive),+); $crate::_nt_array_deref_impls!($name, f64); };
($name:ident, String, $n:expr) => { $crate::_nt_array_string!($name, $n); $crate::_nt_array_deref_impls!($name, String); };
($name:ident, String, $n:expr; $($derive:path),+) => { $crate::_nt_array_string!($name, $n; $($derive),+); $crate::_nt_array_deref_impls!($name, String); };
($name:ident, $t:ty, $n:expr) => { $crate::_nt_array_generic!($name, $t, $n); $crate::_nt_array_deref_impls!($name, $t); };
($name:ident, $t:ty, $n:expr; $($derive:path),+) => { $crate::_nt_array_generic!($name, $t, $n; $($derive),+); $crate::_nt_array_deref_impls!($name, $t); };
}
#[macro_export]
macro_rules! newtype_from {
($name:ident, i8) => {
$crate::_nt_int_from!($name, i8);
};
($name:ident, u8) => {
$crate::_nt_int_from!($name, u8);
};
($name:ident, i16) => {
$crate::_nt_int_from!($name, i16);
};
($name:ident, u16) => {
$crate::_nt_int_from!($name, u16);
};
($name:ident, i32) => {
$crate::_nt_int_from!($name, i32);
};
($name:ident, u32) => {
$crate::_nt_int_from!($name, u32);
};
($name:ident, i64) => {
$crate::_nt_int_from!($name, i64);
};
($name:ident, u64) => {
$crate::_nt_int_from!($name, u64);
};
($name:ident, i128) => {
$crate::_nt_int_from!($name, i128);
};
($name:ident, u128) => {
$crate::_nt_int_from!($name, u128);
};
($name:ident, isize) => {
$crate::_nt_int_from!($name, isize);
};
($name:ident, usize) => {
$crate::_nt_int_from!($name, usize);
};
($name:ident, f32) => {
$crate::_nt_float_from!($name, f32);
};
($name:ident, f64) => {
$crate::_nt_float_from!($name, f64);
};
($name:ident, String) => {
impl From<String> for $name {
#[inline(always)]
fn from(value: String) -> Self {
$name(value)
}
}
impl From<&str> for $name {
#[inline(always)]
fn from(value: &str) -> Self {
$name(value.into())
}
}
impl std::str::FromStr for $name {
type Err = std::convert::Infallible;
#[inline(always)]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok($name(String::from_str(s).unwrap()))
}
}
};
($name:ident, $inner:ty) => {
impl From<$inner> for $name {
#[inline(always)]
fn from(value: $inner) -> Self {
$name(value)
}
}
};
}
#[macro_export]
macro_rules! newtype_from_only {
($name:ident, i8) => {
$crate::_nt_from_traits!($name, i8);
};
($name:ident, u8) => {
$crate::_nt_from_traits!($name, u8);
};
($name:ident, i16) => {
$crate::_nt_from_traits!($name, i16);
};
($name:ident, u16) => {
$crate::_nt_from_traits!($name, u16);
};
($name:ident, i32) => {
$crate::_nt_from_traits!($name, i32);
};
($name:ident, u32) => {
$crate::_nt_from_traits!($name, u32);
};
($name:ident, i64) => {
$crate::_nt_from_traits!($name, i64);
};
($name:ident, u64) => {
$crate::_nt_from_traits!($name, u64);
};
($name:ident, i128) => {
$crate::_nt_from_traits!($name, i128);
};
($name:ident, u128) => {
$crate::_nt_from_traits!($name, u128);
};
($name:ident, isize) => {
$crate::_nt_from_traits!($name, isize);
};
($name:ident, usize) => {
$crate::_nt_from_traits!($name, usize);
};
($name:ident, f32) => {
$crate::_nt_from_traits!($name, f32);
};
($name:ident, f64) => {
$crate::_nt_from_traits!($name, f64);
};
($name:ident, String) => {
impl From<String> for $name {
#[inline(always)]
fn from(value: String) -> Self {
$name(value)
}
}
impl From<&str> for $name {
#[inline(always)]
fn from(value: &str) -> Self {
$name(value.into())
}
}
};
($name:ident, $inner:ty) => {
$crate::_nt_from_traits!($name, $inner);
};
}
#[macro_export]
macro_rules! newtype_fromstr {
($name:ident, i8) => {
$crate::_nt_fromstr_traits!($name, i8, std::num::ParseIntError);
};
($name:ident, u8) => {
$crate::_nt_fromstr_traits!($name, u8, std::num::ParseIntError);
};
($name:ident, i16) => {
$crate::_nt_fromstr_traits!($name, i16, std::num::ParseIntError);
};
($name:ident, u16) => {
$crate::_nt_fromstr_traits!($name, u16, std::num::ParseIntError);
};
($name:ident, i32) => {
$crate::_nt_fromstr_traits!($name, i32, std::num::ParseIntError);
};
($name:ident, u32) => {
$crate::_nt_fromstr_traits!($name, u32, std::num::ParseIntError);
};
($name:ident, i64) => {
$crate::_nt_fromstr_traits!($name, i64, std::num::ParseIntError);
};
($name:ident, u64) => {
$crate::_nt_fromstr_traits!($name, u64, std::num::ParseIntError);
};
($name:ident, i128) => {
$crate::_nt_fromstr_traits!($name, i128, std::num::ParseIntError);
};
($name:ident, u128) => {
$crate::_nt_fromstr_traits!($name, u128, std::num::ParseIntError);
};
($name:ident, isize) => {
$crate::_nt_fromstr_traits!($name, isize, std::num::ParseIntError);
};
($name:ident, usize) => {
$crate::_nt_fromstr_traits!($name, usize, std::num::ParseIntError);
};
($name:ident, f32) => {
$crate::_nt_fromstr_traits!($name, f32, std::num::ParseFloatError);
};
($name:ident, f64) => {
$crate::_nt_fromstr_traits!($name, f64, std::num::ParseFloatError);
};
($name:ident, String) => {
impl std::str::FromStr for $name {
type Err = std::convert::Infallible;
#[inline(always)]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok($name(String::from_str(s).unwrap()))
}
}
};
}
#[cfg(test)]
mod tests_newtype {
newtype!(UserId, u32);
newtype_from!(UserId, u32);
newtype!(Weight, f32);
newtype_from!(Weight, f32);
newtype!(StrId, String);
newtype_from!(StrId, String);
#[test]
fn test_integers_cmp() {
let v1 = UserId::from(42);
let v2 = UserId::from(1001);
let v3 = UserId::from(42);
assert!(v1 != v2);
assert!(v2 != v3);
assert!(v1 == v1);
assert!(v1 == v3);
}
#[test]
#[allow(clippy::clone_on_copy)]
fn test_integers_copy() {
let v1 = UserId::from(42);
let v2 = UserId::from(1001);
#[allow(unused)]
let mut v3 = UserId::from(0);
v3 = v1;
assert_eq!(UserId(42), v3);
v3 = v2;
assert_eq!(UserId(1001), v3);
v3 = v1.clone();
assert_eq!(UserId(42), v3);
v3 = v2.clone();
assert_eq!(UserId(1001), v3);
}
#[test]
fn test_integers_into() {
let v1 = UserId::from(42);
assert_eq!(42_u32, v1.into());
}
#[test]
fn test_float_cmp() {
let v1 = Weight::from(42.0);
let v2 = Weight::from(1001.0);
let v3 = Weight::from(42.0);
assert!(v1 != v2);
assert!(v2 != v3);
assert!(v1 == v1);
assert!(v1 == v3);
}
#[test]
#[allow(clippy::clone_on_copy)]
fn test_float_copy() {
let v1 = Weight::from(42.0);
let v2 = Weight::from(1001.0);
#[allow(unused)]
let mut v3 = Weight::from(0.0);
v3 = v1;
assert_eq!(Weight(42.0), v3);
v3 = v2;
assert_eq!(Weight(1001.0), v3);
v3 = v1.clone();
assert_eq!(Weight(42.0), v3);
v3 = v2.clone();
assert_eq!(Weight(1001.0), v3);
}
#[test]
fn test_float_into() {
let v1 = Weight::from(42.0);
assert_eq!(42_f32, v1.into());
}
#[test]
fn test_string_cmp() {
let v1 = StrId::from("42");
let v2 = StrId::from("1001");
let v3 = StrId::from("42");
assert!(v1 != v2);
assert!(v2 != v3);
assert!(v1 == v1);
assert!(v1 == v3);
}
#[test]
fn test_string_copy() {
let v1 = StrId::from("42");
let v2 = StrId::from("1001");
#[allow(unused)]
let mut v3 = StrId::from("0");
v3 = v1.clone();
assert_eq!(StrId("42".into()), v3);
v3 = v2.clone();
assert_eq!(StrId("1001".into()), v3);
}
#[test]
fn test_string_into() {
let v1 = StrId::from("42");
let s: String = v1.into();
assert_eq!("42", s);
}
}
#[cfg(test)]
mod tests_newtype_ord {
newtype_ord!(Weight, u32);
newtype_from!(Weight, u32);
newtype_ord!(Height, f32);
newtype_from!(Height, f32);
newtype_ord!(Name, String);
newtype_from!(Name, String);
#[test]
fn test_integers_cmp() {
let w1 = Weight::from(100);
let w2 = Weight::from(150);
assert!(w1 <= w2);
assert!(w1 < w2);
assert!(w2 >= w1);
assert!(w2 > w1);
}
#[test]
fn test_float_cmp() {
let h1 = Height::from(100.0);
let h2 = Height::from(150.0);
assert!(h1 <= h2);
assert!(h1 < h2);
assert!(h2 >= h1);
assert!(h2 > h1);
}
#[test]
fn test_string_cmp() {
let n1 = Name::from("Alan");
let n2 = Name::from("Julia");
assert!(n1 <= n2);
assert!(n1 < n2);
assert!(n2 >= n1);
assert!(n2 > n1);
}
}
#[cfg(test)]
mod tests_newtype_unit {
newtype_unit!(Units, i32);
newtype_from!(Units, i32);
#[test]
fn test_integers_add() {
let u1 = Units::from(100);
let u2 = Units::from(50);
let mut u3 = Units::from(200);
assert_eq!(Units(150), u1 + u2);
assert_eq!(Units(150), u2 + u1);
u3 += u2;
assert_eq!(Units(250), u3);
}
#[test]
fn test_integers_sub() {
let u1 = Units::from(100);
let u2 = Units::from(50);
let mut u3 = Units::from(200);
assert_eq!(Units(50), u1 - u2);
assert_eq!(Units(-50), u2 - u1);
u3 -= u2;
assert_eq!(Units(150), u3);
}
}
#[cfg(test)]
mod tests_newtype_from {
use std::str::FromStr;
newtype!(UserId, u32);
newtype_from!(UserId, u32);
newtype!(Weight, f32);
newtype_from!(Weight, f32);
newtype!(Name, String);
newtype_from!(Name, String);
#[test]
fn test_integer_fromstr() {
assert_eq!(Ok(UserId(42)), UserId::from_str("42"));
assert!(UserId::from_str("hello").is_err());
}
#[test]
fn test_float_fromstr() {
assert_eq!(Ok(Weight(42.0)), Weight::from_str("42.0"));
assert!(Weight::from_str("hello").is_err());
}
#[test]
fn test_string_fromstr() {
assert_eq!(Ok(Name("John".into())), Name::from_str("John"));
}
}
#[cfg(test)]
mod tests_newtype_from_split {
use std::str::FromStr;
newtype!(IntFromOnly, u32);
newtype_from_only!(IntFromOnly, u32);
newtype!(FloatFromOnly, f32);
newtype_from_only!(FloatFromOnly, f32);
newtype!(StrFromOnly, String);
newtype_from_only!(StrFromOnly, String);
#[derive(Debug)]
pub struct Inner(u32);
newtype!(StructFromOnly, Inner);
newtype_from_only!(StructFromOnly, Inner);
newtype!(IntFromStr, u32);
newtype_fromstr!(IntFromStr, u32);
newtype!(FloatFromStr, f32);
newtype_fromstr!(FloatFromStr, f32);
newtype!(StrFromStr, String);
newtype_fromstr!(StrFromStr, String);
newtype!(BothInt, u32);
newtype_from_only!(BothInt, u32);
newtype_fromstr!(BothInt, u32);
#[test]
fn test_from_only_integer() {
let v: IntFromOnly = 42_u32.into();
let n: u32 = v.into();
assert_eq!(42, n);
}
#[test]
fn test_from_only_float() {
let v: FloatFromOnly = 1.5_f32.into();
let n: f32 = v.into();
assert!((n - 1.5).abs() < f32::EPSILON);
}
#[test]
fn test_from_only_string_owned() {
let v: StrFromOnly = String::from("hello").into();
let s: String = v.into();
assert_eq!("hello", s);
}
#[test]
fn test_from_only_string_slice() {
let v: StrFromOnly = "world".into();
let s: String = v.into();
assert_eq!("world", s);
}
#[test]
fn test_from_only_struct() {
let v: StructFromOnly = Inner(7).into();
let inner: Inner = v.into();
assert_eq!(7, inner.0);
}
#[test]
fn test_fromstr_integer() {
let v = IntFromStr::from_str("99").unwrap();
assert_eq!(99_u32, v.into());
assert!(IntFromStr::from_str("nope").is_err());
}
#[test]
fn test_fromstr_float() {
let v = FloatFromStr::from_str("3.25").unwrap();
let n: f32 = v.into();
assert!((n - 3.25).abs() < f32::EPSILON);
assert!(FloatFromStr::from_str("nope").is_err());
}
#[test]
fn test_fromstr_string() {
let v = StrFromStr::from_str("greetings").unwrap();
let s: String = v.into();
assert_eq!("greetings", s);
}
#[test]
fn test_combined_equivalent_to_newtype_from() {
let from_int: BothInt = 7_u32.into();
let parsed = BothInt::from_str("7").unwrap();
assert_eq!(7_u32, from_int.into());
assert_eq!(7_u32, parsed.into());
}
}
#[cfg(test)]
mod tests_newtype_struct {
#[derive(Debug, Clone, PartialEq)]
pub struct Point2D {
pub x: f32,
pub y: f32,
}
newtype_struct!(Vertex, Point2D);
newtype_struct!(Numbers, Vec<u32>);
#[derive(Debug, Clone, PartialEq)]
struct Container {
head: Vertex,
tail: Vertex,
}
#[test]
fn test_struct_clone_and_eq() {
let a = Vertex(Point2D { x: 1.0, y: 2.0 });
let b = a.clone();
assert_eq!(a, b);
let c = Vertex(Point2D { x: 1.0, y: 3.0 });
assert!(a != c);
}
#[test]
fn test_struct_into() {
let v = Vertex(Point2D { x: 4.0, y: 5.0 });
let inner: Point2D = v.into();
assert_eq!(Point2D { x: 4.0, y: 5.0 }, inner);
}
#[test]
fn test_struct_debug() {
let v = Vertex(Point2D { x: 0.0, y: 0.0 });
let dbg = format!("{:?}", v);
assert!(dbg.contains("Vertex"));
assert!(dbg.contains("Point2D"));
}
#[test]
fn test_struct_wrapping_vec() {
let n = Numbers(vec![1, 2, 3]);
let m = n.clone();
assert_eq!(n, m);
let inner: Vec<u32> = n.into();
assert_eq!(vec![1, 2, 3], inner);
}
#[test]
fn test_struct_composes_in_outer_struct() {
let c1 = Container {
head: Vertex(Point2D { x: 0.0, y: 0.0 }),
tail: Vertex(Point2D { x: 1.0, y: 1.0 }),
};
let c2 = c1.clone();
assert_eq!(c1, c2);
}
}
#[cfg(test)]
mod tests_newtype_validated {
use std::error::Error;
newtype_validated!(Probability, ProbabilityError, f32, |x: &f32| (0.0..=1.0)
.contains(x));
fn is_even(x: &u32) -> bool {
x.is_multiple_of(2)
}
newtype_validated!(EvenU32, EvenU32Error, u32, is_even);
newtype_validated!(NonEmpty, NonEmptyError, String, |s: &String| !s.is_empty());
#[derive(Debug, Clone, PartialEq)]
pub struct Range {
pub lo: i32,
pub hi: i32,
}
newtype_validated!(SortedRange, SortedRangeError, Range, |r: &Range| r.lo
<= r.hi);
#[test]
fn test_closure_validator_valid() {
let p = Probability::new(0.5).unwrap();
let inner: f32 = p.into();
assert!((inner - 0.5).abs() < f32::EPSILON);
}
#[test]
fn test_closure_validator_invalid() {
assert_eq!(Err(ProbabilityError), Probability::new(2.0));
assert_eq!(Err(ProbabilityError), Probability::new(-0.1));
}
#[test]
fn test_closure_validator_boundaries() {
assert!(Probability::new(0.0).is_ok());
assert!(Probability::new(1.0).is_ok());
}
#[test]
fn test_function_path_validator() {
assert!(EvenU32::new(4).is_ok());
assert_eq!(Err(EvenU32Error), EvenU32::new(5));
}
#[test]
fn test_string_validator() {
assert!(NonEmpty::new("hello".to_string()).is_ok());
assert_eq!(Err(NonEmptyError), NonEmpty::new(String::new()));
}
#[test]
fn test_struct_validator() {
assert!(SortedRange::new(Range { lo: 1, hi: 5 }).is_ok());
assert_eq!(
Err(SortedRangeError),
SortedRange::new(Range { lo: 5, hi: 1 })
);
}
#[test]
fn test_tryfrom_valid() {
let p: Probability = (0.5_f32).try_into().unwrap();
let inner: f32 = p.into();
assert!((inner - 0.5).abs() < f32::EPSILON);
}
#[test]
fn test_tryfrom_invalid() {
let r: Result<Probability, _> = (2.0_f32).try_into();
assert_eq!(Err(ProbabilityError), r);
}
#[test]
fn test_error_traits() {
let e = ProbabilityError;
let dbg = format!("{:?}", e);
assert!(dbg.contains("ProbabilityError"));
let disp = format!("{}", e);
assert_eq!("invalid Probability value", disp);
let copy = e;
assert_eq!(e, copy);
let _src: Option<&(dyn Error + 'static)> = e.source();
}
#[test]
fn test_clone_and_eq_on_validated_value() {
let a = Probability::new(0.25).unwrap();
let b = a.clone();
assert_eq!(a, b);
}
}
#[cfg(test)]
mod tests_pointer_sized_ints {
use std::str::FromStr;
newtype!(UsizeId, usize);
newtype_from!(UsizeId, usize);
newtype_ord!(UsizeOrd, usize);
newtype_from!(UsizeOrd, usize);
newtype_unit!(UsizeUnit, usize);
newtype_from!(UsizeUnit, usize);
newtype!(UsizeOnly, usize);
newtype_from_only!(UsizeOnly, usize);
newtype!(UsizeStr, usize);
newtype_fromstr!(UsizeStr, usize);
newtype!(IsizeId, isize);
newtype_from!(IsizeId, isize);
newtype_ord!(IsizeOrd, isize);
newtype_from!(IsizeOrd, isize);
newtype_unit!(IsizeUnit, isize);
newtype_from!(IsizeUnit, isize);
newtype!(IsizeOnly, isize);
newtype_from_only!(IsizeOnly, isize);
newtype!(IsizeStr, isize);
newtype_fromstr!(IsizeStr, isize);
#[test]
fn test_usize_basics() {
let a = UsizeId::from(42);
let b = UsizeId::from(42);
let c = UsizeId::from(7);
assert_eq!(a, b);
assert!(a != c);
let n: usize = a.into();
assert_eq!(42, n);
}
#[test]
fn test_usize_ord() {
let a = UsizeOrd::from(1);
let b = UsizeOrd::from(2);
assert!(a < b);
}
#[test]
fn test_usize_unit_arithmetic() {
let a = UsizeUnit::from(10);
let b = UsizeUnit::from(3);
let c = a + b;
let n: usize = c.into();
assert_eq!(13, n);
}
#[test]
fn test_usize_fromstr_via_newtype_from() {
assert_eq!(Ok(UsizeId(99)), UsizeId::from_str("99"));
assert!(UsizeId::from_str("nope").is_err());
}
#[test]
fn test_usize_from_only() {
let a = UsizeOnly::from(5);
let n: usize = a.into();
assert_eq!(5, n);
}
#[test]
fn test_usize_fromstr_only() {
let a = UsizeStr::from_str("123").unwrap();
let n: usize = a.into();
assert_eq!(123, n);
}
#[test]
fn test_isize_basics() {
let a = IsizeId::from(-42);
let b = IsizeId::from(-42);
let c = IsizeId::from(7);
assert_eq!(a, b);
assert!(a != c);
let n: isize = a.into();
assert_eq!(-42, n);
}
#[test]
fn test_isize_ord() {
let a = IsizeOrd::from(-1);
let b = IsizeOrd::from(2);
assert!(a < b);
}
#[test]
fn test_isize_unit_arithmetic() {
let a = IsizeUnit::from(10);
let b = IsizeUnit::from(-3);
let c = a + b;
let n: isize = c.into();
assert_eq!(7, n);
}
#[test]
fn test_isize_fromstr_via_newtype_from() {
assert_eq!(Ok(IsizeId(-99)), IsizeId::from_str("-99"));
assert!(IsizeId::from_str("nope").is_err());
}
#[test]
fn test_isize_from_only() {
let a = IsizeOnly::from(-5);
let n: isize = a.into();
assert_eq!(-5, n);
}
#[test]
fn test_isize_fromstr_only() {
let a = IsizeStr::from_str("-123").unwrap();
let n: isize = a.into();
assert_eq!(-123, n);
}
}
#[cfg(test)]
mod tests_layout {
use std::mem::{align_of, size_of};
newtype!(LayoutI8, i8);
newtype!(LayoutU64, u64);
newtype!(LayoutI128, i128);
newtype!(LayoutF32, f32);
newtype!(LayoutF64, f64);
newtype!(LayoutString, String);
#[derive(Debug)]
#[allow(dead_code)]
struct Wide {
a: u64,
b: u32,
}
newtype!(LayoutStruct, Wide);
#[test]
fn test_size_matches_inner() {
assert_eq!(size_of::<i8>(), size_of::<LayoutI8>());
assert_eq!(size_of::<u64>(), size_of::<LayoutU64>());
assert_eq!(size_of::<i128>(), size_of::<LayoutI128>());
assert_eq!(size_of::<f32>(), size_of::<LayoutF32>());
assert_eq!(size_of::<f64>(), size_of::<LayoutF64>());
assert_eq!(size_of::<String>(), size_of::<LayoutString>());
assert_eq!(size_of::<Wide>(), size_of::<LayoutStruct>());
}
#[test]
fn test_align_matches_inner() {
assert_eq!(align_of::<i8>(), align_of::<LayoutI8>());
assert_eq!(align_of::<u64>(), align_of::<LayoutU64>());
assert_eq!(align_of::<i128>(), align_of::<LayoutI128>());
assert_eq!(align_of::<f32>(), align_of::<LayoutF32>());
assert_eq!(align_of::<f64>(), align_of::<LayoutF64>());
assert_eq!(align_of::<String>(), align_of::<LayoutString>());
assert_eq!(align_of::<Wide>(), align_of::<LayoutStruct>());
}
}
#[cfg(test)]
mod tests_newtype_array {
newtype_array!(Mac, u8, 6);
newtype_array!(Floats, f32, 4);
newtype_array!(Names, String, 2);
newtype_array!(Empty, u8, 0);
#[derive(Debug, Clone, PartialEq)]
pub struct Tag(pub u32);
newtype_array!(Tags, Tag, 3);
#[test]
fn test_index_usize() {
let m = Mac([1, 2, 3, 4, 5, 6]);
assert_eq!(1, m[0]);
assert_eq!(6, m[5]);
}
#[test]
fn test_index_mut_usize() {
let mut m = Mac([0; 6]);
m[0] = 42;
m[5] = 7;
assert_eq!(42, m[0]);
assert_eq!(7, m[5]);
}
#[test]
fn test_range_index() {
let m = Mac([1, 2, 3, 4, 5, 6]);
let s: &[u8] = &m[1..3];
assert_eq!(&[2u8, 3], s);
let s: &[u8] = &m[..];
assert_eq!(&[1u8, 2, 3, 4, 5, 6], s);
let s: &[u8] = &m[2..];
assert_eq!(&[3u8, 4, 5, 6], s);
let s: &[u8] = &m[..=1];
assert_eq!(&[1u8, 2], s);
}
#[test]
fn test_range_index_mut() {
let mut m = Mac([1, 2, 3, 4, 5, 6]);
m[1..3].copy_from_slice(&[20, 30]);
assert_eq!(20, m[1]);
assert_eq!(30, m[2]);
}
#[test]
fn test_iter_inherent() {
let m = Mac([1, 2, 3, 4, 5, 6]);
let sum: u32 = m.iter().map(|&x| x as u32).sum();
assert_eq!(21, sum);
}
#[test]
fn test_iter_mut_inherent() {
let mut m = Mac([1, 2, 3, 4, 5, 6]);
for x in m.iter_mut() {
*x *= 2;
}
assert_eq!(2, m[0]);
assert_eq!(12, m[5]);
}
#[test]
fn test_into_iter_ref() {
let m = Mac([1, 2, 3, 4, 5, 6]);
let sum: u32 = (&m).into_iter().map(|&x| x as u32).sum();
assert_eq!(21, sum);
}
#[test]
fn test_into_iter_owned() {
let m = Mac([1, 2, 3, 4, 5, 6]);
let v: Vec<u8> = m.into_iter().collect();
assert_eq!(vec![1u8, 2, 3, 4, 5, 6], v);
}
#[test]
fn test_for_loop_ref() {
let m = Mac([1, 2, 3, 4, 5, 6]);
let mut total: u32 = 0;
for x in &m {
total += *x as u32;
}
assert_eq!(21, total);
}
#[test]
fn test_for_loop_mut() {
let mut m = Mac([1, 2, 3, 4, 5, 6]);
for x in &mut m {
*x += 1;
}
assert_eq!(2, m[0]);
assert_eq!(7, m[5]);
}
#[test]
fn test_len_and_is_empty() {
let m = Mac([0; 6]);
assert_eq!(6, m.len());
assert!(!m.is_empty());
let e = Empty([]);
assert_eq!(0, e.len());
assert!(e.is_empty());
}
#[test]
fn test_as_array() {
let m = Mac([1, 2, 3, 4, 5, 6]);
let a: &[u8; 6] = m.as_array();
assert_eq!(&[1u8, 2, 3, 4, 5, 6], a);
}
#[test]
fn test_as_array_mut() {
let mut m = Mac([0; 6]);
m.as_array_mut()[0] = 9;
assert_eq!(9, m[0]);
}
#[test]
fn test_into_array() {
let m = Mac([1, 2, 3, 4, 5, 6]);
let a: [u8; 6] = m.into();
assert_eq!([1u8, 2, 3, 4, 5, 6], a);
}
#[test]
fn test_as_ref_slice() {
let m = Mac([1, 2, 3, 4, 5, 6]);
let s: &[u8] = m.as_ref();
assert_eq!(&[1u8, 2, 3, 4, 5, 6], s);
}
#[test]
fn test_as_mut_slice() {
let mut m = Mac([1, 2, 3, 4, 5, 6]);
let s: &mut [u8] = m.as_mut();
s[0] = 99;
assert_eq!(99, m[0]);
}
#[test]
fn test_eq_and_hash_for_int_array() {
use std::collections::HashSet;
let a = Mac([1, 2, 3, 4, 5, 6]);
let b = Mac([1, 2, 3, 4, 5, 6]);
let c = Mac([6, 5, 4, 3, 2, 1]);
assert_eq!(a, b);
assert!(a != c);
let mut set: HashSet<Mac> = HashSet::new();
set.insert(a);
assert!(set.contains(&b));
assert!(!set.contains(&c));
}
#[test]
fn test_copy_for_int_array() {
let a = Mac([1, 2, 3, 4, 5, 6]);
let b = a;
let c = a;
assert_eq!(a, b);
assert_eq!(a, c);
}
#[test]
fn test_float_array_partialeq() {
let a = Floats([1.0, 2.0, 3.0, 4.0]);
let b = Floats([1.0, 2.0, 3.0, 4.0]);
let c = Floats([1.0, 2.0, 3.0, 5.0]);
assert!(a == b);
assert!(a != c);
}
#[test]
fn test_string_array() {
let n = Names(["alice".into(), "bob".into()]);
let m = n.clone();
assert_eq!(n, m);
assert_eq!("alice", n[0]);
assert_eq!("bob", n[1]);
}
#[test]
fn test_generic_struct_array() {
let t = Tags([Tag(1), Tag(2), Tag(3)]);
let u = t.clone();
assert_eq!(t, u);
assert_eq!(Tag(2), t[1]);
}
#[test]
fn test_empty_array_iter() {
let e = Empty([]);
let count = e.iter().count();
assert_eq!(0, count);
let count = e.into_iter().count();
assert_eq!(0, count);
}
}
#[cfg(test)]
mod tests_newtype_array_deref {
newtype_array_deref!(Buf, u8, 4);
#[test]
fn test_deref_slice_methods() {
let b = Buf([1, 2, 3, 4]);
assert_eq!(Some(&1u8), b.first());
assert_eq!(Some(&4u8), b.last());
assert!(b.contains(&3));
assert!(!b.contains(&99));
}
#[test]
fn test_deref_mut_slice_method() {
let mut b = Buf([1, 2, 3, 4]);
b.fill(0);
assert_eq!([0u8, 0, 0, 0], *b.as_array());
}
#[test]
fn test_deref_target_is_slice() {
let b = Buf([10, 20, 30, 40]);
let s: &[u8] = &b;
assert_eq!(&[10u8, 20, 30, 40], s);
}
#[test]
fn test_deref_does_not_break_inherent_iter() {
let b = Buf([1, 2, 3, 4]);
let sum: u32 = b.iter().map(|&x| x as u32).sum();
assert_eq!(10, sum);
}
}
#[cfg(test)]
mod tests_newtype_array_layout {
use std::mem::{align_of, size_of};
newtype_array!(LU8x6, u8, 6);
newtype_array!(LU64x4, u64, 4);
newtype_array!(LF32x3, f32, 3);
newtype_array_deref!(LDU8x4, u8, 4);
#[test]
fn test_size_matches_inner() {
assert_eq!(size_of::<[u8; 6]>(), size_of::<LU8x6>());
assert_eq!(size_of::<[u64; 4]>(), size_of::<LU64x4>());
assert_eq!(size_of::<[f32; 3]>(), size_of::<LF32x3>());
assert_eq!(size_of::<[u8; 4]>(), size_of::<LDU8x4>());
}
#[test]
fn test_align_matches_inner() {
assert_eq!(align_of::<[u8; 6]>(), align_of::<LU8x6>());
assert_eq!(align_of::<[u64; 4]>(), align_of::<LU64x4>());
assert_eq!(align_of::<[f32; 3]>(), align_of::<LF32x3>());
assert_eq!(align_of::<[u8; 4]>(), align_of::<LDU8x4>());
}
}