use core::fmt;
use core::marker::PhantomData;
use thiserror::Error;
use crate::{core::Predicate, logic::Not, static_str::StaticStr};
pub trait HasEmpty {
fn empty(&self) -> bool;
}
#[derive(Debug, Error, Default)]
#[error("received non-empty value")]
pub struct EmptyError;
impl EmptyError {
pub const fn new() -> Self {
Self
}
}
pub const VALUE: StaticStr = "empty value";
pub const EMPTY: StaticStr = "empty";
pub struct Empty {
private: PhantomData<()>,
}
impl<T: HasEmpty + ?Sized> Predicate<T> for Empty {
type Error = EmptyError;
fn check(value: &T) -> Result<(), Self::Error> {
if value.empty() {
Ok(())
} else {
Err(Self::Error::new())
}
}
fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(VALUE)
}
fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(EMPTY)
}
}
pub type NonEmpty = Not<Empty>;
impl HasEmpty for str {
fn empty(&self) -> bool {
self.is_empty()
}
}
impl<T> HasEmpty for [T] {
fn empty(&self) -> bool {
self.is_empty()
}
}
impl<T: HasEmpty + ?Sized> HasEmpty for &T {
fn empty(&self) -> bool {
T::empty(self)
}
}
#[cfg(feature = "alloc")]
use alloc::{boxed::Box, string::String, vec::Vec};
#[cfg(any(feature = "alloc", feature = "std"))]
impl<T: HasEmpty + ?Sized> HasEmpty for Box<T> {
fn empty(&self) -> bool {
T::empty(self)
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl HasEmpty for String {
fn empty(&self) -> bool {
self.is_empty()
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl<T> HasEmpty for Vec<T> {
fn empty(&self) -> bool {
self.is_empty()
}
}
#[cfg(feature = "alloc")]
use alloc::borrow::{Cow, ToOwned};
#[cfg(all(not(feature = "alloc"), feature = "std"))]
use std::borrow::{Cow, ToOwned};
#[cfg(any(feature = "alloc", feature = "std"))]
impl<T: ToOwned + HasEmpty + ?Sized> HasEmpty for Cow<'_, T> {
fn empty(&self) -> bool {
T::empty(self)
}
}
#[cfg(feature = "alloc")]
use alloc::rc::Rc;
#[cfg(all(not(feature = "alloc"), feature = "std"))]
use std::rc::Rc;
#[cfg(any(feature = "alloc", feature = "std"))]
impl<T: HasEmpty + ?Sized> HasEmpty for Rc<T> {
fn empty(&self) -> bool {
T::empty(self)
}
}
#[cfg(feature = "alloc")]
use alloc::sync::Arc;
#[cfg(all(not(feature = "alloc"), feature = "std"))]
use std::sync::Arc;
#[cfg(any(feature = "alloc", feature = "std"))]
impl<T: HasEmpty + ?Sized> HasEmpty for Arc<T> {
fn empty(&self) -> bool {
T::empty(self)
}
}
#[cfg(feature = "alloc")]
use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
#[cfg(all(not(feature = "alloc"), feature = "std"))]
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
#[cfg(any(feature = "alloc", feature = "std"))]
impl<K, V> HasEmpty for BTreeMap<K, V> {
fn empty(&self) -> bool {
self.is_empty()
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl<T> HasEmpty for BTreeSet<T> {
fn empty(&self) -> bool {
self.is_empty()
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl<T> HasEmpty for BinaryHeap<T> {
fn empty(&self) -> bool {
self.is_empty()
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl<T> HasEmpty for LinkedList<T> {
fn empty(&self) -> bool {
self.is_empty()
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl<T> HasEmpty for VecDeque<T> {
fn empty(&self) -> bool {
self.is_empty()
}
}
#[cfg(feature = "std")]
use std::collections::{HashMap, HashSet};
#[cfg(feature = "std")]
impl<K, V, S> HasEmpty for HashMap<K, V, S> {
fn empty(&self) -> bool {
self.is_empty()
}
}
#[cfg(feature = "std")]
impl<T, S> HasEmpty for HashSet<T, S> {
fn empty(&self) -> bool {
self.is_empty()
}
}
#[cfg(feature = "std")]
use std::ffi::{OsStr, OsString};
#[cfg(feature = "std")]
impl HasEmpty for OsStr {
fn empty(&self) -> bool {
self.is_empty()
}
}
#[cfg(feature = "std")]
impl HasEmpty for OsString {
fn empty(&self) -> bool {
self.is_empty()
}
}
#[cfg(feature = "std")]
use std::path::{Path, PathBuf};
#[cfg(feature = "std")]
impl HasEmpty for Path {
fn empty(&self) -> bool {
self.as_os_str().is_empty()
}
}
#[cfg(feature = "std")]
impl HasEmpty for PathBuf {
fn empty(&self) -> bool {
self.as_os_str().is_empty()
}
}