use core::{
error::Error as StdError,
fmt, hash,
marker::PhantomData,
mem::discriminant,
ops::{Deref, DerefMut},
};
use constr::Constr;
use crate::{
spair::Spair,
traits::{Stringable, Stringy},
};
#[derive(Copy, Clone)]
struct State(usize);
impl State {
const SHIFT: u32 = usize::BITS - 2;
const FIRST: State = State(0b01 << State::SHIFT);
const SECOND: State = State(0b10 << State::SHIFT);
const NEITHER: State = State(0b11 << State::SHIFT);
fn new(split: usize) -> State {
State(split)
}
fn has_first(&self) -> bool {
self.0 & State::FIRST.0 != State::FIRST.0
}
fn has_second(&self) -> bool {
self.0 & State::SECOND.0 != State::SECOND.0
}
fn as_split(&self) -> Option<usize> {
(self.0 & State::NEITHER.0 == 0).then_some(self.0)
}
}
pub struct Custom<E, K1: Constr, K2: Constr> {
err: E,
marker: PhantomData<(K1, K2)>,
}
impl<E, K1: Constr, K2: Constr> Custom<E, K1, K2> {
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
pub fn into_inner(self) -> E {
self.err
}
}
impl<E, K1: Constr, K2: Constr> Deref for Custom<E, K1, K2> {
type Target = E;
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn deref(&self) -> &E {
&self.err
}
}
impl<E, K1: Constr, K2: Constr> DerefMut for Custom<E, K1, K2> {
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn deref_mut(&mut self) -> &mut E {
&mut self.err
}
}
impl<E: Copy, K1: Constr, K2: Constr> Copy for Custom<E, K1, K2> {}
impl<E: Clone, K1: Constr, K2: Constr> Clone for Custom<E, K1, K2> {
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn clone(&self) -> Self {
Custom {
err: self.err.clone(),
marker: PhantomData,
}
}
}
impl<L: PartialEq<R>, R, K1: Constr, K2: Constr> PartialEq<Custom<R, K1, K2>>
for Custom<L, K1, K2>
{
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn eq(&self, other: &Custom<R, K1, K2>) -> bool {
self.err == other.err
}
}
impl<E: Eq, K1: Constr, K2: Constr> Eq for Custom<E, K1, K2> {}
impl<E: hash::Hash, K1: Constr, K2: Constr> hash::Hash for Custom<E, K1, K2> {
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.err.hash(state);
}
}
impl<S: AsRef<str>, K1: Constr, K2: Constr> StdError for CustomIncompleteError<S, K1, K2> {}
impl<S: AsRef<str>, K1: Constr, K2: Constr> fmt::Debug for CustomIncompleteError<S, K1, K2> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (first, second) = self.pair();
let mut err = f.debug_struct("IncompleteError");
match first {
Some(first) => {
err.field(K1::STR, &first);
}
None => {
err.field(K1::STR, &format_args!("_"));
}
}
match second {
Some(second) => {
err.field(K2::STR, &second);
}
None => {
err.field(K2::STR, &format_args!("_"));
}
}
err.finish()
}
}
impl<S: AsRef<str>, K1: Constr, K2: Constr> StdError for CustomDuplicateError<S, K1, K2> {}
impl<S: AsRef<str>, K1: Constr, K2: Constr> fmt::Debug for CustomDuplicateError<S, K1, K2> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DuplicateError")
.field("pair", &self.pair())
.field(
"which",
&format_args!(
"{}",
match self.which() {
Duplicated::First => K1::STR,
Duplicated::Second => K2::STR,
}
),
)
.finish()
}
}
impl<S: AsRef<str>, K1: Constr, K2: Constr> fmt::Display for CustomIncompleteError<S, K1, K2> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let k1 = K1::STR;
let k2 = K2::STR;
match &self.err {
IncompleteError::Empty => {
write!(f, "missing {k1} and {k2}")
}
IncompleteError::First(first) => {
let first = first.as_ref();
write!(f, "got {k1} {first:?}, but missing {k2}")
}
IncompleteError::Second(second) => {
let second = second.as_ref();
write!(f, "got {k2} {second:?}, but missing {k1}")
}
}
}
}
impl<S: AsRef<str>, K1: Constr, K2: Constr> fmt::Display for CustomDuplicateError<S, K1, K2> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (first, second) = self.pair();
let which = match self.which {
Duplicated::First => K1::STR,
Duplicated::Second => K2::STR,
};
write!(f, "got duplicate {which}: {first:?} and {second:?}")
}
}
pub type CustomDuplicateError<S, K1, K2> = Custom<DuplicateError<S>, K1, K2>;
pub type CustomIncompleteError<S, K1, K2> = Custom<IncompleteError<S>, K1, K2>;
#[derive(Copy, Clone)]
pub enum IncompleteError<S: AsRef<str>> {
Empty,
First(S),
Second(S),
}
impl<S: AsRef<str>> IncompleteError<S> {
pub fn pair(&self) -> (Option<&str>, Option<&str>) {
match self {
IncompleteError::Empty => (None, None),
IncompleteError::First(buf) => (Some(buf.as_ref()), None),
IncompleteError::Second(buf) => (None, Some(buf.as_ref())),
}
}
pub fn custom<K1: Constr, K2: Constr>(self) -> CustomIncompleteError<S, K1, K2> {
Custom {
err: self,
marker: PhantomData,
}
}
}
impl<S1: AsRef<str>, S2: AsRef<str>> PartialEq<IncompleteError<S2>> for IncompleteError<S1> {
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn eq(&self, other: &IncompleteError<S2>) -> bool {
match (self, other) {
(IncompleteError::Empty, IncompleteError::Empty) => true,
(IncompleteError::First(lhs), IncompleteError::First(rhs))
| (IncompleteError::Second(lhs), IncompleteError::Second(rhs)) => {
lhs.as_ref() == rhs.as_ref()
}
_ => false,
}
}
}
impl<S: AsRef<str>> Eq for IncompleteError<S> {}
impl<S: AsRef<str>> hash::Hash for IncompleteError<S> {
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
let (first, second) = self.pair();
first.as_ref().hash(state);
second.as_ref().hash(state);
}
}
impl<S: AsRef<str>> fmt::Debug for IncompleteError<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (first, second) = self.pair();
let mut tuple = f.debug_tuple("IncompleteError");
match first {
Some(first) => {
tuple.field(&first);
}
None => {
tuple.field(&format_args!("_"));
}
}
match second {
Some(second) => {
tuple.field(&second);
}
None => {
tuple.field(&format_args!("_"));
}
}
tuple.finish()
}
}
impl<S: AsRef<str>> StdError for IncompleteError<S> {}
impl<S: AsRef<str>> fmt::Display for IncompleteError<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (first, second) = self.pair();
write!(f, "unfinished pair: (")?;
match first {
Some(first) => {
write!(f, "{first:?}")?;
}
None => {
write!(f, "_")?;
}
}
write!(f, ", ")?;
match second {
Some(second) => {
write!(f, "{second:?}")?;
}
None => {
write!(f, "_")?;
}
}
write!(f, ")")
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Duplicated {
First,
Second,
}
pub struct DuplicateError<S: AsRef<str>> {
pub(crate) pair: Spair<S>,
pub(crate) which: Duplicated,
}
impl<S: AsRef<str>> DuplicateError<S> {
pub fn spair(&self) -> &Spair<S> {
&self.pair
}
pub fn pair(&self) -> (&str, &str) {
self.pair.pair()
}
pub fn which(&self) -> Duplicated {
self.which
}
pub fn custom<K1: Constr, K2: Constr>(self) -> CustomDuplicateError<S, K1, K2> {
Custom {
err: self,
marker: PhantomData,
}
}
}
impl<S: AsRef<str> + Clone> Clone for DuplicateError<S> {
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn clone(&self) -> Self {
DuplicateError {
pair: self.pair.clone(),
which: self.which,
}
}
}
impl<S1: AsRef<str>, S2: AsRef<str>> PartialEq<DuplicateError<S2>> for DuplicateError<S1> {
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn eq(&self, other: &DuplicateError<S2>) -> bool {
self.which() == other.which() && self.spair() == other.spair()
}
}
impl<S: AsRef<str>> Eq for DuplicateError<S> {}
impl<S: AsRef<str>> hash::Hash for DuplicateError<S> {
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.spair().hash(state);
self.which().hash(state);
}
}
impl<S: AsRef<str> + Copy> Copy for DuplicateError<S> {}
impl<S: AsRef<str>> fmt::Debug for DuplicateError<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DuplicateError")
.field("pair", &self.pair())
.field("which", &self.which)
.finish()
}
}
impl<S: AsRef<str>> StdError for DuplicateError<S> {}
impl<S: AsRef<str>> fmt::Display for DuplicateError<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (first, second) = self.pair();
let which = match self.which {
Duplicated::First => "first",
Duplicated::Second => "second",
};
write!(f, "got duplicate {which} key: {first:?} and {second:?}")
}
}
pub enum BuildError<S: Stringable> {
Duplicate(DuplicateError<S>),
Capacity(<S::Builder as Stringy>::Error),
}
impl<S: Stringable + Clone> Clone for BuildError<S>
where
<S::Builder as Stringy>::Error: Clone,
{
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn clone(&self) -> Self {
match self {
BuildError::Duplicate(err) => BuildError::Duplicate(err.clone()),
BuildError::Capacity(err) => BuildError::Capacity(err.clone()),
}
}
}
impl<S: Stringable + Copy> Copy for BuildError<S> where <S::Builder as Stringy>::Error: Copy {}
impl<S1: Stringable, S2: Stringable> PartialEq<BuildError<S2>> for BuildError<S1>
where
<S1::Builder as Stringy>::Error: PartialEq<<S2::Builder as Stringy>::Error>,
{
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn eq(&self, other: &BuildError<S2>) -> bool {
match (self, other) {
(BuildError::Duplicate(lhs), BuildError::Duplicate(rhs)) => lhs == rhs,
(BuildError::Capacity(lhs), BuildError::Capacity(rhs)) => lhs == rhs,
_ => false,
}
}
}
impl<S: Stringable> hash::Hash for BuildError<S>
where
<S::Builder as Stringy>::Error: hash::Hash,
{
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
discriminant(self).hash(state);
match self {
BuildError::Duplicate(err) => err.hash(state),
BuildError::Capacity(err) => err.hash(state),
}
}
}
impl<S: Stringable> Eq for BuildError<S> where <S::Builder as Stringy>::Error: Eq {}
impl<S: Stringable> fmt::Debug for BuildError<S>
where
<S::Builder as Stringy>::Error: fmt::Debug,
{
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BuildError::Duplicate(err) => fmt::Debug::fmt(err, f),
BuildError::Capacity(err) => fmt::Debug::fmt(err, f),
}
}
}
impl<S: 'static + Stringable> StdError for BuildError<S>
where
<S::Builder as Stringy>::Error: 'static + StdError,
{
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
BuildError::Duplicate(err) => Some(err),
BuildError::Capacity(err) => Some(err),
}
}
}
impl<S: Stringable> fmt::Display for BuildError<S>
where
<S::Builder as Stringy>::Error: fmt::Display,
{
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BuildError::Duplicate(err) => fmt::Display::fmt(err, f),
BuildError::Capacity(err) => fmt::Display::fmt(err, f),
}
}
}
pub fn act<S: Stringable, Sep: Constr, const SPLIT_SEP: bool>() -> Act<S, Sep, SPLIT_SEP> {
Act {
buf: S::Builder::new(),
state: State::NEITHER,
phantom: PhantomData,
}
}
pub struct Act<S: Stringable, Sep: Constr = constr::Empty, const SPLIT_SEP: bool = false> {
buf: S::Builder,
state: State,
phantom: PhantomData<Sep>,
}
impl<S: Stringable, Sep: Constr, const SPLIT_SEP: bool> Act<S, Sep, SPLIT_SEP> {
pub fn first<F: AsRef<str>>(mut self, s: F) -> Result<Act<S, Sep, SPLIT_SEP>, BuildError<S>> {
let s = s.as_ref();
if self.state.has_first() {
if let Some(mut split) = self.state.as_split() {
if SPLIT_SEP {
split -= Sep::STR.len();
}
self.buf.truncate_back(split);
}
let split = self.buf.len();
self.buf.push_back(s).map_err(BuildError::Capacity)?;
Err(BuildError::Duplicate(DuplicateError {
pair: unsafe { Spair::split_unchecked(self.buf.into(), split) },
which: Duplicated::First,
}))
} else if self.state.has_second() {
let mut split = self.buf.len();
if SPLIT_SEP {
split += Sep::STR.len();
}
self.buf
.push_front_many(&[s, Sep::STR])
.map_err(BuildError::Capacity)?;
self.state = State::new(split);
Ok(self)
} else {
self.buf.push_back(s).map_err(BuildError::Capacity)?;
self.state = State::SECOND;
Ok(self)
}
}
pub fn second<F: AsRef<str>>(mut self, s: F) -> Result<Act<S, Sep, SPLIT_SEP>, BuildError<S>> {
let s = s.as_ref();
if self.state.has_second() {
if let Some(mut split) = self.state.as_split() {
if !SPLIT_SEP {
split += Sep::STR.len();
}
self.buf.remove_front(split);
}
let split = self.buf.len();
self.buf.push_back(s).map_err(BuildError::Capacity)?;
Err(BuildError::Duplicate(DuplicateError {
pair: unsafe { Spair::split_unchecked(self.buf.into(), split) },
which: Duplicated::Second,
}))
} else if self.state.has_first() {
let mut split = self.buf.len();
if SPLIT_SEP {
split += Sep::STR.len();
}
self.buf
.push_back_many(&[Sep::STR, s])
.map_err(BuildError::Capacity)?;
self.state = State::new(split);
Ok(self)
} else {
self.buf.push_back(s).map_err(BuildError::Capacity)?;
self.state = State::FIRST;
Ok(self)
}
}
pub fn finish(self) -> Result<Spair<S, Sep, SPLIT_SEP>, IncompleteError<S>> {
if let Some(split) = self.state.as_split() {
Ok(unsafe { Spair::split_unchecked(self.buf.into(), split) })
} else if self.state.has_first() {
Err(IncompleteError::First(self.buf.into()))
} else if self.state.has_second() {
Err(IncompleteError::Second(self.buf.into()))
} else {
Err(IncompleteError::Empty)
}
}
}
impl<S: Stringable<Builder: Copy>, Sep: Constr, const SPLIT_SEP: bool> Copy
for Act<S, Sep, SPLIT_SEP>
{
}
impl<S: Stringable<Builder: Clone>, Sep: Constr, const SPLIT_SEP: bool> Clone
for Act<S, Sep, SPLIT_SEP>
{
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn clone(&self) -> Self {
Act {
buf: self.buf.clone(),
state: self.state,
phantom: PhantomData,
}
}
}
impl<S: Stringable, Sep: Constr, const SPLIT_SEP: bool> fmt::Debug for Act<S, Sep, SPLIT_SEP> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(split) = self.state.as_split() {
let pair =
unsafe { <Spair<&str, Sep, SPLIT_SEP>>::split_unchecked(self.buf.as_ref(), split) };
let (first, second) = pair.pair();
f.debug_tuple("Act").field(&first).field(&second).finish()
} else if self.state.has_first() {
f.debug_tuple("Act")
.field(&self.buf.as_ref())
.field(&format_args!("_"))
.finish()
} else if self.state.has_second() {
f.debug_tuple("Act")
.field(&format_args!("_"))
.field(&self.buf.as_ref())
.finish()
} else {
f.debug_tuple("Act")
.field(&format_args!("_"))
.field(&format_args!("_"))
.finish()
}
}
}