use core::{
alloc::{AllocError, Layout, LayoutError},
error::Error,
fmt,
};
#[derive(Clone, PartialEq, Eq)]
enum AllocateErrorInternal {
Layout { error: LayoutError },
Alloc { error: AllocError, layout: Layout },
}
#[derive(Clone, PartialEq, Eq)]
pub struct AllocateError<Value = ()> {
internal: AllocateErrorInternal,
value: Value,
}
impl AllocateErrorInternal {
fn handle(self) -> ! {
#[cfg(feature = "alloc")]
crate::alloc::handle_alloc_error(match self {
Self::Layout { .. } => Layout::new::<()>(),
Self::Alloc { layout, .. } => layout,
});
#[cfg(not(feature = "alloc"))]
panic!("{self}")
}
}
impl<Value> AllocateError<Value> {
#[inline]
pub fn handle(self) -> ! {
self.internal.handle()
}
#[inline]
pub fn into_value(self) -> Value {
self.value
}
#[inline]
pub fn into_parts(self) -> (Value, AllocateError) {
(
self.value,
AllocateError {
internal: self.internal,
value: (),
},
)
}
#[inline]
pub fn unwrap_result<T>(result: Result<T, Self>) -> T {
match result {
Ok(value) => value,
Err(err) => err.handle(),
}
}
#[inline]
pub const fn layout(&self) -> Option<Layout> {
match self.internal {
AllocateErrorInternal::Layout { .. } => None,
AllocateErrorInternal::Alloc { layout, .. } => Some(layout),
}
}
#[inline]
pub fn map<U, F>(self, f: F) -> AllocateError<U>
where
F: FnOnce(Value) -> U,
{
let (value, empty) = self.into_parts();
empty.with_value(f(value))
}
}
impl AllocateError {
#[inline]
pub const fn with_value<Value>(self, value: Value) -> AllocateError<Value> {
AllocateError {
internal: self.internal,
value,
}
}
#[must_use]
#[inline]
pub const fn new_layout(source: LayoutError) -> Self {
Self {
internal: AllocateErrorInternal::Layout { error: source },
value: (),
}
}
#[must_use]
#[inline]
pub const fn new_alloc(source: AllocError, layout: Layout) -> Self {
Self {
internal: AllocateErrorInternal::Alloc {
error: source,
layout,
},
value: (),
}
}
}
impl fmt::Debug for AllocateErrorInternal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut tuple;
match self {
Self::Layout { .. } => {
tuple = f.debug_tuple("AllocateError::Layout");
}
Self::Alloc { layout, .. } => {
tuple = f.debug_tuple("AllocateError::Alloc");
tuple.field(&layout);
}
}
tuple.finish()
}
}
impl fmt::Display for AllocateErrorInternal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Layout { error } => write!(f, "{error}"),
Self::Alloc { error, layout } => write!(
f,
"{error} (size: {}, align: {})",
layout.size(),
layout.align()
),
}
}
}
impl fmt::Debug for AllocateError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.internal, f)
}
}
impl fmt::Display for AllocateError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.internal, f)
}
}
impl Error for AllocateErrorInternal {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(match self {
Self::Layout { error } => error,
Self::Alloc { error, .. } => error,
})
}
}
impl Error for AllocateError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.internal.source()
}
}
impl From<LayoutError> for AllocateError {
#[inline]
fn from(value: LayoutError) -> Self {
Self::new_layout(value)
}
}
impl<Value> From<AllocateError<Value>> for AllocError {
#[inline]
fn from(_value: AllocateError<Value>) -> Self {
Self
}
}