#[cfg(feature = "alloc")]
use alloc::boxed::Box;
use core::error::Error;
use core::fmt::{Debug, Display, Formatter};
use core::iter::Chain;
use core::ops::Deref;
use display_as_debug::fmt::DebugStructExt;
use display_as_debug::wrap::Full;
use nameof::name_of;
use tap::Pipe;
use super::ErrorItemProvider;
#[cfg(doc)]
use crate::errors::capacity::CapacityErrorKind;
pub struct ExtendError<I, E> {
#[cfg(doc)]
pub remain: I,
#[cfg(doc)]
pub error: E,
#[cfg(all(not(doc), feature = "alloc"))]
data: Box<ExtendErrorData<I, E>>,
#[cfg(all(not(doc), not(feature = "alloc")))]
data: ExtendErrorData<I, E>,
}
#[doc(hidden)]
pub struct ExtendErrorData<I, E> {
pub remain: I,
pub error: E,
}
impl<I, E> ExtendError<I, E> {
#[must_use]
#[cfg(feature = "alloc")]
pub fn new(remain: I, error: E) -> Self {
ExtendErrorData { remain, error }.pipe(Box::new).pipe(|data| Self { data })
}
#[must_use]
#[cfg(not(feature = "alloc"))]
pub fn new(remain: I, error: E) -> Self {
ExtendErrorData { remain, error }.pipe(|data| Self { data })
}
#[must_use]
#[cfg(feature = "alloc")]
pub fn into_data(self) -> ExtendErrorData<I, E> {
*self.data
}
#[must_use]
#[cfg(not(feature = "alloc"))]
pub fn into_data(self) -> ExtendErrorData<I, E> {
self.data
}
}
impl<I: Iterator, E> IntoIterator for ExtendError<I, E>
where
E: ErrorItemProvider<Item = I::Item>,
{
type Item = I::Item;
type IntoIter = Chain<core::option::IntoIter<I::Item>, I>;
fn into_iter(self) -> Self::IntoIter {
self.data.into_iter()
}
}
impl<I, E: Display> Display for ExtendError<I, E> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "Extension Error: {}", self.error)
}
}
impl<I, E: Error + 'static> Error for ExtendError<I, E> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(&self.error)
}
}
impl<I, E: Debug> Debug for ExtendError<I, E> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ExtendError")
.field_type::<I, Full>(name_of!(remain in Self))
.field(name_of!(error in Self), &self.error)
.finish()
}
}
#[doc(hidden)]
impl<I, E> Deref for ExtendError<I, E> {
type Target = ExtendErrorData<I, E>;
fn deref(&self) -> &Self::Target {
&self.data
}
}
#[doc(hidden)]
#[allow(clippy::missing_fields_in_debug, reason = "All data is covered")]
impl<I, E: Debug> Debug for ExtendErrorData<I, E> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ExtendErrorData")
.field_type::<I, Full>(name_of!(remain in Self))
.field(name_of!(error in Self), &self.error)
.finish()
}
}
#[doc(hidden)]
impl<I, E: Display> Display for ExtendErrorData<I, E> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "Extension Error: {}", self.error)
}
}
#[doc(hidden)]
impl<I, E: Error + 'static> Error for ExtendErrorData<I, E> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(&self.error)
}
}
#[doc(hidden)]
impl<I: Iterator, E> IntoIterator for ExtendErrorData<I, E>
where
E: ErrorItemProvider<Item = I::Item>,
{
type Item = I::Item;
type IntoIter = Chain<core::option::IntoIter<I::Item>, I>;
fn into_iter(self) -> Self::IntoIter {
self.error.into_item().into_iter().chain(self.remain)
}
}