use crate::{Tagged, ViaString, refine::*};
use derive_more::Display;
use num_traits::*;
use std::convert::Infallible;
use std::error::Error;
use std::fmt::Debug;
use std::marker::PhantomData;
use tap::prelude::*;
#[derive(Debug)]
pub enum FCrude {}
impl<T> Refine<T> for FCrude {
type RefineError = Infallible;
}
#[derive(Debug)]
pub enum FPositive {}
#[derive(
Eq,
PartialEq,
Ord,
PartialOrd,
Copy,
Clone,
Debug,
Display,
)]
#[display("{:?}", self)]
pub struct PositiveError<T>(pub T)
where
T: Debug;
impl<T> Error for PositiveError<T> where T: Debug {}
impl<T> Refine<T> for FPositive
where
T: PartialOrd + Zero + Debug,
{
type RefineError = PositiveError<T>;
fn refine(rep: T) -> Result<T, Self::RefineError> {
if rep > Zero::zero() {
Ok(rep)
} else {
PositiveError(rep).pipe(Err)
}
}
}
#[derive(Debug)]
pub enum FNonNeg {}
#[derive(
Eq,
PartialEq,
Ord,
PartialOrd,
Copy,
Clone,
Debug,
Display,
)]
#[display("{:?}", self)]
pub struct NonNegError<T>(pub T)
where
T: Debug;
impl<T> Error for NonNegError<T> where T: Debug {}
impl<T> Refine<T> for FNonNeg
where
T: PartialOrd + Zero + Debug,
{
type RefineError = NonNegError<T>;
fn refine(rep: T) -> Result<T, Self::RefineError> {
if rep >= Zero::zero() {
Ok(rep)
} else {
NonNegError(rep).pipe(Err)
}
}
}
#[derive(Debug)]
pub enum FZeroExclToOneExcl {}
#[derive(
Eq,
PartialEq,
Ord,
PartialOrd,
Copy,
Clone,
Debug,
Display,
)]
#[display("{:?}", self)]
pub struct ZeroExclToOneExclError<T>(pub T)
where
T: Debug;
impl<T> Error for ZeroExclToOneExclError<T> where T: Debug {}
impl<T> Refine<T> for FZeroExclToOneExcl
where
T: PartialOrd + Zero + One + Debug,
{
type RefineError = ZeroExclToOneExclError<T>;
fn refine(rep: T) -> Result<T, Self::RefineError> {
if rep > Zero::zero() && rep < One::one() {
Ok(rep)
} else {
ZeroExclToOneExclError(rep).pipe(Err)
}
}
}
#[derive(Debug)]
pub enum FZeroInclToOneExcl {}
#[derive(
Eq,
PartialEq,
Ord,
PartialOrd,
Copy,
Clone,
Debug,
Display,
)]
#[display("{:?}", self)]
pub struct ZeroInclToOneExclError<T>(pub T)
where
T: Debug;
impl<T> Error for ZeroInclToOneExclError<T> where T: Debug {}
impl<T> Refine<T> for FZeroInclToOneExcl
where
T: PartialOrd + Zero + One + Debug,
{
type RefineError = ZeroInclToOneExclError<T>;
fn refine(rep: T) -> Result<T, Self::RefineError> {
if rep >= Zero::zero() && rep < One::one() {
Ok(rep)
} else {
ZeroInclToOneExclError(rep).pipe(Err)
}
}
}
#[derive(Debug)]
pub enum FZeroExclToOneIncl {}
#[derive(
Eq,
PartialEq,
Ord,
PartialOrd,
Copy,
Clone,
Debug,
Display,
)]
#[display("{:?}", self)]
pub struct ZeroExclToOneInclError<T>(pub T)
where
T: Debug;
impl<T> Error for ZeroExclToOneInclError<T> where T: Debug {}
impl<T> Refine<T> for FZeroExclToOneIncl
where
T: PartialOrd + Zero + One + Debug,
{
type RefineError = ZeroExclToOneInclError<T>;
fn refine(rep: T) -> Result<T, Self::RefineError> {
if rep > Zero::zero() && rep <= One::one() {
Ok(rep)
} else {
ZeroExclToOneInclError(rep).pipe(Err)
}
}
}
#[derive(Debug)]
pub enum FZeroInclToOneIncl {}
#[derive(
Eq,
PartialEq,
Ord,
PartialOrd,
Copy,
Clone,
Debug,
Display,
)]
#[display("{:?}", self)]
pub struct ZeroInclToOneInclError<T>(pub T)
where
T: Debug;
impl<T> Error for ZeroInclToOneInclError<T> where T: Debug {}
impl<T> Refine<T> for FZeroInclToOneIncl
where
T: PartialOrd + Zero + One + Debug,
{
type RefineError = ZeroInclToOneInclError<T>;
fn refine(rep: T) -> Result<T, Self::RefineError> {
if rep >= Zero::zero() && rep <= One::one() {
Ok(rep)
} else {
ZeroInclToOneInclError(rep).pipe(Err)
}
}
}
pub type NonEmpty<T> = Tagged<T, FNonEmpty, FNonEmpty>;
#[derive(Debug)]
pub enum FNonEmpty {}
#[derive(
Eq,
PartialEq,
Ord,
PartialOrd,
Copy,
Clone,
Debug,
Display,
)]
#[display("{:?}", self)]
pub struct NonEmptyError<T>(pub PhantomData<T>)
where
T: Debug;
impl<T> Error for NonEmptyError<T> where T: Debug {}
impl<T> Refine<T> for FNonEmpty
where
T: Debug + HasLength,
{
type RefineError = NonEmptyError<T>;
fn refine(rep: T) -> Result<T, Self::RefineError> {
if rep.zero_length() {
NonEmptyError(PhantomData).pipe(Err)
} else {
Ok(rep)
}
}
}
pub trait HasLength {
fn length(&self) -> usize;
fn zero_length(&self) -> bool {
self.length() == 0
}
}
impl<T: HasLength, D, F> HasLength for Tagged<T, D, F> {
fn length(&self) -> usize {
(**self).length()
}
}
impl<T: HasLength, D, F> HasLength for ViaString<T, D, F> {
fn length(&self) -> usize {
(**self).length()
}
}
impl<T: HasLength + ?Sized> HasLength for &T {
fn length(&self) -> usize {
(**self).length()
}
}
impl<T: HasLength + ?Sized> HasLength for &mut T {
fn length(&self) -> usize {
(**self).length()
}
}
impl<T> HasLength for [T] {
fn length(&self) -> usize {
self.len()
}
}
impl<T, const N: usize> HasLength for [T; N] {
fn length(&self) -> usize {
N
}
}
impl HasLength for str {
fn length(&self) -> usize {
self.len()
}
}
impl HasLength for String {
fn length(&self) -> usize {
self.len()
}
}
impl HasLength for std::path::Path {
fn length(&self) -> usize {
self.as_os_str().len()
}
}
impl HasLength for std::path::PathBuf {
fn length(&self) -> usize {
self.as_os_str().len()
}
}
impl HasLength for std::ffi::OsStr {
fn length(&self) -> usize {
self.len()
}
}
impl HasLength for std::ffi::OsString {
fn length(&self) -> usize {
self.len()
}
}
impl HasLength for std::ffi::CStr {
fn length(&self) -> usize {
self.to_bytes().len()
}
}
impl HasLength for std::ffi::CString {
fn length(&self) -> usize {
self.as_bytes().len()
}
}
impl<T> HasLength for Box<T>
where
T: HasLength + ?Sized,
{
fn length(&self) -> usize {
(**self).length()
}
}
impl<T> HasLength for std::borrow::Cow<'_, T>
where
T: HasLength + ?Sized + ToOwned,
{
fn length(&self) -> usize {
(**self).length()
}
}
impl<T> HasLength for std::rc::Rc<T>
where
T: HasLength + ?Sized,
{
fn length(&self) -> usize {
(**self).length()
}
}
impl<T> HasLength for std::sync::Arc<T>
where
T: HasLength + ?Sized,
{
fn length(&self) -> usize {
(**self).length()
}
}
impl<T> HasLength for Vec<T> {
fn length(&self) -> usize {
self.len()
}
}
impl<T, S> HasLength for std::collections::HashSet<T, S> {
fn length(&self) -> usize {
self.len()
}
}
impl<K, V, S> HasLength
for std::collections::HashMap<K, V, S>
{
fn length(&self) -> usize {
self.len()
}
}
impl<T> HasLength for std::collections::BTreeSet<T> {
fn length(&self) -> usize {
self.len()
}
}
impl<K, V> HasLength for std::collections::BTreeMap<K, V> {
fn length(&self) -> usize {
self.len()
}
}
impl<T> HasLength for std::collections::VecDeque<T> {
fn length(&self) -> usize {
self.len()
}
}
impl<T> HasLength for std::collections::LinkedList<T> {
fn length(&self) -> usize {
self.len()
}
}
impl<T> HasLength for std::collections::BinaryHeap<T> {
fn length(&self) -> usize {
self.len()
}
}