use core::{marker::PhantomData, mem::size_of, num::ParseIntError};
use crate::err::Error;
pub trait FallibleMap<I, O> {
fn out_size(&self) -> usize {
size_of::<O>()
}
fn try_map(&self, val: I) -> Result<O, Error>;
}
impl<I, O, F> FallibleMap<I, O> for F
where
F: Fn(I) -> Result<O, Error>,
{
fn try_map(&self, val: I) -> Result<O, Error> {
(self)(val)
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct FuncMapper<F> {
func: F,
}
impl<F> FuncMapper<F> {
pub const fn new(func: F) -> Self {
Self { func }
}
}
impl<F, I, O> FallibleMap<I, O> for FuncMapper<F>
where
F: Fn(I) -> O,
{
fn try_map(&self, val: I) -> Result<O, Error> {
Ok((self.func)(val))
}
}
pub const fn mapper<F>(func: F) -> FuncMapper<F> {
FuncMapper::new(func)
}
#[derive(Debug, Clone, Copy, Default)]
pub struct Select0;
impl Select0 {
pub const fn new() -> Self {
Self {}
}
}
impl<I1, I2> FallibleMap<(I1, I2), I1> for Select0 {
fn try_map(&self, val: (I1, I2)) -> Result<I1, Error> {
Ok(val.0)
}
}
pub const fn select0() -> Select0 {
Select0::new()
}
#[derive(Debug, Clone, Copy, Default)]
pub struct Select1;
impl Select1 {
pub const fn new() -> Self {
Self {}
}
}
impl<I1, I2> FallibleMap<(I1, I2), I2> for Select1 {
fn try_map(&self, val: (I1, I2)) -> Result<I2, Error> {
Ok(val.1)
}
}
pub const fn select1() -> Select1 {
Select1::new()
}
#[derive(Debug, Clone, Copy, Default)]
pub struct SelectEq;
impl SelectEq {
pub const fn new() -> Self {
Self {}
}
}
impl<I1, I2> FallibleMap<(I1, I2), (I1, I2)> for SelectEq
where
I1: PartialEq<I2>,
{
fn try_map(&self, val: (I1, I2)) -> Result<(I1, I2), Error> {
if val.0 == val.1 {
Ok(val)
} else {
Err(Error::SelectEq)
}
}
}
pub const fn select_eq() -> SelectEq {
SelectEq::new()
}
#[derive(Debug, Clone, Copy, Default)]
pub struct SelectNeq;
impl SelectNeq {
pub const fn new() -> Self {
Self {}
}
}
impl<I1, I2> FallibleMap<(I1, I2), (I1, I2)> for SelectNeq
where
I1: PartialEq<I2>,
{
fn try_map(&self, val: (I1, I2)) -> Result<(I1, I2), Error> {
if val.0 != val.1 {
Ok(val)
} else {
Err(Error::SelectNeq)
}
}
}
pub const fn select_neq() -> SelectNeq {
SelectNeq::new()
}
#[derive(Debug)]
pub struct FromStr<T>(PhantomData<T>);
impl<T> Clone for FromStr<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for FromStr<T> {}
impl<T> Default for FromStr<T> {
fn default() -> Self {
Self(Default::default())
}
}
impl<T> FromStr<T> {
pub const fn new() -> Self {
Self(PhantomData)
}
}
impl<I, O> FallibleMap<I, O> for FromStr<O>
where
O: core::str::FromStr,
I: AsRef<str>,
{
fn try_map(&self, val: I) -> Result<O, Error> {
let val: &str = val.as_ref();
val.parse::<O>().map_err(|_| Error::FromStr)
}
}
pub const fn from_str<T>() -> FromStr<T> {
FromStr::new()
}
#[derive(Debug)]
pub struct IntoMapper<T>(PhantomData<T>);
impl<T> Clone for IntoMapper<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for IntoMapper<T> {}
impl<T> IntoMapper<T> {
pub const fn new() -> Self {
Self(PhantomData)
}
}
impl<T> Default for IntoMapper<T> {
fn default() -> Self {
Self(Default::default())
}
}
impl<I, O> FallibleMap<I, O> for IntoMapper<O>
where
O: From<I>,
{
fn try_map(&self, val: I) -> Result<O, Error> {
Ok(val.into())
}
}
pub const fn into<T>() -> IntoMapper<T> {
IntoMapper::new()
}
#[derive(Debug)]
pub struct TryIntoMapper<T>(PhantomData<T>);
impl<T> Clone for TryIntoMapper<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for TryIntoMapper<T> {}
impl<T> TryIntoMapper<T> {
pub const fn new() -> Self {
Self(PhantomData)
}
}
impl<T> Default for TryIntoMapper<T> {
fn default() -> Self {
Self(Default::default())
}
}
impl<I, O> FallibleMap<I, O> for TryIntoMapper<O>
where
O: TryFrom<I>,
{
fn try_map(&self, val: I) -> Result<O, Error> {
val.try_into().map_err(|_| Error::TryInto)
}
}
pub const fn try_into<T>() -> TryIntoMapper<T> {
TryIntoMapper::new()
}
pub trait TryFromStrRadix
where
Self: Sized,
{
fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError>;
}
macro_rules! impl_from_str_radix {
($int:ty) => {
impl $crate::map::TryFromStrRadix for $int {
#[inline(always)]
fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
<$int>::from_str_radix(src, radix)
}
}
};
}
impl_from_str_radix!(i8);
impl_from_str_radix!(i16);
impl_from_str_radix!(i32);
impl_from_str_radix!(i64);
impl_from_str_radix!(isize);
impl_from_str_radix!(u8);
impl_from_str_radix!(u16);
impl_from_str_radix!(u32);
impl_from_str_radix!(u64);
impl_from_str_radix!(usize);
#[derive(Debug)]
pub struct FromStrRadix<T> {
radix: u32,
marker: PhantomData<T>,
}
impl<T> Clone for FromStrRadix<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for FromStrRadix<T> {}
impl<T> Default for FromStrRadix<T> {
fn default() -> Self {
Self {
radix: Default::default(),
marker: Default::default(),
}
}
}
impl<T> FromStrRadix<T>
where
T: TryFromStrRadix,
{
pub const fn new(radix: u32) -> Self {
Self {
radix,
marker: PhantomData,
}
}
pub const fn radix(&self) -> u32 {
self.radix
}
}
impl<I, O> FallibleMap<I, O> for FromStrRadix<O>
where
O: TryFromStrRadix,
I: AsRef<str>,
{
#[inline(always)]
fn try_map(&self, val: I) -> Result<O, Error> {
O::from_str_radix(val.as_ref(), self.radix()).map_err(|_| Error::FromStr)
}
}
#[inline(always)]
pub const fn from_str_radix<T: TryFromStrRadix>(radix: u32) -> FromStrRadix<T> {
FromStrRadix::new(radix)
}
#[derive(Debug)]
pub struct FromUtf8<T>(PhantomData<T>);
impl<T> FromUtf8<T> {
pub const fn new() -> Self {
Self(PhantomData)
}
}
impl<T> Clone for FromUtf8<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for FromUtf8<T> {}
impl<T> Default for FromUtf8<T> {
fn default() -> Self {
Self(Default::default())
}
}
impl<'a> FallibleMap<&'a [u8], &'a str> for FromUtf8<&'a str> {
fn try_map(&self, val: &'a [u8]) -> Result<&'a str, Error> {
core::str::from_utf8(val).map_err(|_| Error::Utf8Error)
}
}
#[cfg(feature = "alloc")]
impl<'a> FallibleMap<&'a [u8], crate::alloc::String> for FromUtf8<crate::alloc::String> {
fn try_map(&self, val: &'a [u8]) -> Result<crate::alloc::String, Error> {
crate::alloc::String::from_utf8(val.to_vec()).map_err(|_| Error::Utf8Error)
}
}
#[inline(always)]
pub const fn from_utf8<T>() -> FromUtf8<T> {
FromUtf8::new()
}
#[derive(Debug)]
pub struct FromUtf8Lossy<T>(PhantomData<T>);
impl<T> FromUtf8Lossy<T> {
pub const fn new() -> Self {
Self(PhantomData)
}
}
impl<T> Clone for FromUtf8Lossy<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for FromUtf8Lossy<T> {}
impl<T> Default for FromUtf8Lossy<T> {
fn default() -> Self {
Self(Default::default())
}
}
#[cfg(feature = "alloc")]
impl<'a> FallibleMap<&'a [u8], crate::alloc::Cow<'a, str>>
for FromUtf8Lossy<crate::alloc::Cow<'a, str>>
{
fn try_map(&self, val: &'a [u8]) -> Result<crate::alloc::Cow<'a, str>, Error> {
Ok(crate::alloc::String::from_utf8_lossy(val))
}
}
#[cfg(feature = "alloc")]
#[inline(always)]
pub const fn from_utf8_lossy<T>() -> FromUtf8Lossy<T> {
FromUtf8Lossy::new()
}
#[derive(Debug)]
pub struct FromLeBytes<T>(PhantomData<T>);
impl<T> FromLeBytes<T> {
pub const fn new() -> Self {
Self(PhantomData)
}
pub const fn size(&self) -> usize {
size_of::<T>()
}
}
impl<T> Clone for FromLeBytes<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for FromLeBytes<T> {}
impl<T> Default for FromLeBytes<T> {
fn default() -> Self {
Self(Default::default())
}
}
#[derive(Debug)]
pub struct FromBeBytes<T>(PhantomData<T>);
impl<T> FromBeBytes<T> {
pub const fn new() -> Self {
Self(PhantomData)
}
pub const fn size(&self) -> usize {
size_of::<T>()
}
}
impl<T> Clone for FromBeBytes<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for FromBeBytes<T> {}
impl<T> Default for FromBeBytes<T> {
fn default() -> Self {
Self(Default::default())
}
}
#[derive(Debug)]
pub struct FromNeBytes<T>(PhantomData<T>);
impl<T> FromNeBytes<T> {
pub const fn new() -> Self {
Self(PhantomData)
}
pub const fn size(&self) -> usize {
size_of::<T>()
}
}
impl<T> Copy for FromNeBytes<T> {}
impl<T> Clone for FromNeBytes<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Default for FromNeBytes<T> {
fn default() -> Self {
Self(Default::default())
}
}
macro_rules! impl_from_bytes {
(le $ty:ty, $size:literal) => {
impl<'a> FallibleMap<&'a [u8], $ty> for FromLeBytes<$ty> {
fn try_map(&self, val: &'a [u8]) -> Result<$ty, $crate::err::Error> {
debug_assert_eq!($size, self.size());
let bytes = val
.chunks_exact($size)
.next()
.ok_or_else(|| $crate::err::Error::FromLeBytes)
.map(|v| {
<&[u8; $size]>::try_from(v).map_err(|_| $crate::err::Error::FromLeBytes)
})??;
Ok(<$ty>::from_le_bytes(*bytes))
}
}
};
(be $ty:ty, $size:literal) => {
impl<'a> FallibleMap<&'a [u8], $ty> for FromBeBytes<$ty> {
fn try_map(&self, val: &'a [u8]) -> Result<$ty, $crate::err::Error> {
debug_assert_eq!($size, self.size());
let bytes = val
.chunks_exact($size)
.next()
.ok_or_else(|| $crate::err::Error::FromBeBytes)
.map(|v| {
<&[u8; $size]>::try_from(v).map_err(|_| $crate::err::Error::FromBeBytes)
})??;
Ok(<$ty>::from_be_bytes(*bytes))
}
}
};
(ne $ty:ty, $size:literal) => {
impl<'a> FallibleMap<&'a [u8], $ty> for FromNeBytes<$ty> {
fn try_map(&self, val: &'a [u8]) -> Result<$ty, $crate::err::Error> {
debug_assert_eq!($size, self.size());
let bytes = val
.chunks_exact($size)
.next()
.ok_or_else(|| $crate::err::Error::FromNeBytes)
.map(|v| {
<&[u8; $size]>::try_from(v).map_err(|_| $crate::err::Error::FromNeBytes)
})??;
Ok(<$ty>::from_ne_bytes(*bytes))
}
}
};
}
impl_from_bytes!(le i8, 1);
impl_from_bytes!(le u8, 1);
impl_from_bytes!(le i16, 2);
impl_from_bytes!(le u16, 2);
impl_from_bytes!(le i32, 4);
impl_from_bytes!(le u32, 4);
impl_from_bytes!(le i64, 8);
impl_from_bytes!(le u64, 8);
impl_from_bytes!(le f32, 4);
impl_from_bytes!(le f64, 8);
impl_from_bytes!(le i128, 16);
impl_from_bytes!(le u128, 16);
impl_from_bytes!(le isize, 8);
impl_from_bytes!(le usize, 8);
impl_from_bytes!(be i8, 1);
impl_from_bytes!(be u8, 1);
impl_from_bytes!(be i16, 2);
impl_from_bytes!(be u16, 2);
impl_from_bytes!(be i32, 4);
impl_from_bytes!(be u32, 4);
impl_from_bytes!(be i64, 8);
impl_from_bytes!(be u64, 8);
impl_from_bytes!(be f32, 4);
impl_from_bytes!(be f64, 8);
impl_from_bytes!(be i128, 16);
impl_from_bytes!(be u128, 16);
impl_from_bytes!(be isize, 8);
impl_from_bytes!(be usize, 8);
impl_from_bytes!(ne i8, 1);
impl_from_bytes!(ne u8, 1);
impl_from_bytes!(ne i16, 2);
impl_from_bytes!(ne u16, 2);
impl_from_bytes!(ne i32, 4);
impl_from_bytes!(ne u32, 4);
impl_from_bytes!(ne i64, 8);
impl_from_bytes!(ne u64, 8);
impl_from_bytes!(ne f32, 4);
impl_from_bytes!(ne f64, 8);
impl_from_bytes!(ne i128, 16);
impl_from_bytes!(ne u128, 16);
impl_from_bytes!(ne isize, 8);
impl_from_bytes!(ne usize, 8);
#[inline(always)]
pub const fn from_le_bytes<T>() -> FromLeBytes<T> {
FromLeBytes::new()
}
#[inline(always)]
pub const fn from_be_bytes<T>() -> FromBeBytes<T> {
FromBeBytes::new()
}
#[inline(always)]
pub const fn from_ne_bytes<T>() -> FromNeBytes<T> {
FromNeBytes::new()
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Bounded<T> {
min: T,
max: T,
}
impl<T> Bounded<T> {
pub const fn new(min: T, max: T) -> Self {
Self { min, max }
}
}
impl<T> FallibleMap<T, T> for Bounded<T>
where
T: PartialOrd,
{
fn try_map(&self, val: T) -> Result<T, Error> {
if self.min <= val && val < self.max {
Ok(val)
} else {
Err(Error::SelectEq)
}
}
}
#[inline(always)]
pub const fn bounded<T: PartialOrd>(min: T, max: T) -> Bounded<T> {
Bounded::new(min, max)
}
#[derive(Debug)]
pub struct WithDefault<I, O, F, M> {
func: F,
mapper: M,
marker: PhantomData<(I, O)>,
}
impl<I, O, F, M> Clone for WithDefault<I, O, F, M>
where
F: Clone,
M: Clone,
{
fn clone(&self) -> Self {
Self {
func: self.func.clone(),
mapper: self.mapper.clone(),
marker: self.marker,
}
}
}
impl<I, O, F, M> Copy for WithDefault<I, O, F, M>
where
F: Copy,
M: Copy,
{
}
impl<I, O, F, M> WithDefault<I, O, F, M>
where
F: Fn() -> O,
M: FallibleMap<I, O>,
{
pub const fn new(func: F, mapper: M) -> Self {
Self {
func,
mapper,
marker: PhantomData,
}
}
}
impl<I, O, F, M> FallibleMap<I, O> for WithDefault<I, O, F, M>
where
F: Fn() -> O,
M: FallibleMap<I, O>,
{
fn out_size(&self) -> usize {
self.mapper.out_size()
}
fn try_map(&self, val: I) -> Result<O, Error> {
if let Ok(val) = self.mapper.try_map(val) {
Ok(val)
} else {
Ok((self.func)())
}
}
}
pub trait WithDefaultHelper<I, O>: Sized {
fn with_default<F>(self, func: F) -> WithDefault<I, O, F, Self>
where
F: Fn() -> O;
}
impl<I, O, T: Sized> WithDefaultHelper<I, O> for T
where
Self: FallibleMap<I, O>,
{
fn with_default<F>(self, func: F) -> WithDefault<I, O, F, Self>
where
F: Fn() -> O,
{
with_default(func, self)
}
}
#[inline(always)]
pub const fn with_default<I, O, F, M>(func: F, mapper: M) -> WithDefault<I, O, F, M>
where
F: Fn() -> O,
M: FallibleMap<I, O>,
{
WithDefault::new(func, mapper)
}
#[derive(Debug, Clone, Copy, Default)]
pub struct FixedSize(pub usize);
impl FixedSize {
pub const fn new(size: usize) -> Self {
Self(size)
}
}
impl<T> FallibleMap<T, T> for FixedSize {
fn out_size(&self) -> usize {
self.0
}
fn try_map(&self, val: T) -> Result<T, Error> {
Ok(val)
}
}
pub const fn fixed_size(size: usize) -> FixedSize {
FixedSize::new(size)
}