pub(super) mod nice_u8;
pub(super) mod nice_u16;
pub(super) mod nice_u32;
pub(super) mod nice_u64;
pub(super) mod nice_float;
pub(super) mod nice_percent;
use std::{
cmp::Ordering,
fmt,
hash::{
Hash,
Hasher,
},
ops::Deref,
};
macro_rules! as_ref_borrow_cast {
($($cast:ident $ty:ty),+ $(,)?) => ($(
impl<const S: usize> AsRef<$ty> for NiceWrapper<S> {
fn as_ref(&self) -> &$ty { self.$cast() }
}
impl<const S: usize> ::std::borrow::Borrow<$ty> for NiceWrapper<S> {
fn borrow(&self) -> &$ty { self.$cast() }
}
)+);
}
#[doc(hidden)]
#[derive(Clone, Copy)]
pub struct NiceWrapper<const S: usize> {
pub(crate) inner: [u8; S],
pub(crate) from: usize,
}
as_ref_borrow_cast!(as_bytes [u8], as_str str);
impl<const S: usize> fmt::Debug for NiceWrapper<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple(&format!("NiceWrapper<{S}>"))
.field(&self.as_str())
.finish()
}
}
impl<const S: usize> Deref for NiceWrapper<S> {
type Target = [u8];
fn deref(&self) -> &Self::Target { self.as_bytes() }
}
impl<const S: usize> fmt::Display for NiceWrapper<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl<const S: usize> Eq for NiceWrapper<S> {}
impl<const S: usize> From<NiceWrapper<S>> for String {
fn from(src: NiceWrapper<S>) -> Self { src.as_str().to_owned() }
}
impl<const S: usize> From<NiceWrapper<S>> for Vec<u8> {
fn from(src: NiceWrapper<S>) -> Self { src.as_bytes().to_vec() }
}
impl<const S: usize, T> From<Option<T>> for NiceWrapper<S>
where Self: From<T> + Default {
fn from(num: Option<T>) -> Self { num.map_or_else(Self::default, Self::from) }
}
impl<const S: usize> Hash for NiceWrapper<S> {
fn hash<H: Hasher>(&self, state: &mut H) { state.write(self.as_bytes()) }
}
impl<const S: usize> Ord for NiceWrapper<S> {
fn cmp(&self, other: &Self) -> Ordering { self.as_bytes().cmp(other.as_bytes()) }
}
impl<const S: usize> PartialEq for NiceWrapper<S> {
fn eq(&self, other: &Self) -> bool { self.as_bytes() == other.as_bytes() }
}
impl<const S: usize> PartialOrd for NiceWrapper<S> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}
impl<const S: usize> NiceWrapper<S> {
#[must_use]
#[inline]
pub fn as_bytes(&self) -> &[u8] { &self.inner[self.from..] }
#[allow(unsafe_code)]
#[must_use]
#[inline]
pub fn as_str(&self) -> &str {
unsafe { std::str::from_utf8_unchecked(self.as_bytes()) }
}
}
#[doc(hidden)]
macro_rules! nice_from_nz {
($nice:ty, $($nz:ty),+ $(,)?) => ($(
impl From<$nz> for $nice {
fn from(num: $nz) -> Self { Self::from(num.get()) }
}
)+);
}
#[doc(hidden)]
macro_rules! nice_default {
($nice:ty, $zero:expr, $size:ident) => (
impl Default for $nice {
fn default() -> Self { Self { inner: $zero, from: $size - 1 } }
}
impl $nice {
#[doc(hidden)]
#[must_use]
pub const fn empty() -> Self { Self { inner: $zero, from: $size } }
}
);
}
#[doc(hidden)]
macro_rules! nice_parse {
($nice:ty, $uint:ty) => (
impl From<$uint> for $nice {
fn from(num: $uint) -> Self {
let mut out = Self::empty();
out.parse(num);
out
}
}
impl $nice {
#[allow(clippy::cast_possible_truncation, unsafe_code)]
fn parse(&mut self, mut num: $uint) {
let ptr = self.inner.as_mut_ptr();
while 999 < num {
let (div, rem) = crate::div_mod(num, 1000);
self.from -= 4;
unsafe { super::write_u8_3(ptr.add(self.from + 1), rem as u16); }
num = div;
}
if 99 < num {
self.from -= 3;
unsafe { super::write_u8_3(ptr.add(self.from), num as u16); }
}
else if 9 < num {
self.from -= 2;
unsafe {
std::ptr::copy_nonoverlapping(
crate::double_ptr(num as usize),
ptr.add(self.from),
2
);
}
}
else {
self.from -= 1;
unsafe { std::ptr::write(ptr.add(self.from), num as u8 + b'0'); }
}
}
}
);
}
pub(self) use {
nice_default,
nice_from_nz,
nice_parse,
};
#[allow(unsafe_code, clippy::cast_possible_truncation)] unsafe fn write_u8_3(buf: *mut u8, num: u16) {
let (div, rem) = crate::div_mod(num, 100);
std::ptr::write(buf, div as u8 + b'0');
std::ptr::copy_nonoverlapping(crate::double_ptr(rem as usize), buf.add(1), 2);
}