use alloc::alloc::Layout;
use core::{
fmt::{Debug, Display, Formatter, Result as FmtResult},
ptr::NonNull,
};
#[derive(Debug)]
#[repr(u8)]
#[cfg_attr(not(feature = "std"), derive(Clone, Copy))]
#[allow(clippy::module_name_repetitions)]
pub enum AllocError {
AllocFailed(Layout, Cause),
#[cfg(feature = "fallible_dealloc")]
DeallocFailed(NonNull<u8>, Layout, Cause),
InvalidLayout(InvLayout),
ZeroSizedLayout(NonNull<u8>),
GrowSmallerNewLayout(usize, usize),
ShrinkBiggerNewLayout(usize, usize),
ArithmeticOverflow(ArithOverflow),
Other(&'static str),
}
impl PartialEq for AllocError {
#[inline]
fn eq(&self, other: &AllocError) -> bool {
use AllocError::{
AllocFailed, ArithmeticOverflow, GrowSmallerNewLayout, InvalidLayout, Other,
ShrinkBiggerNewLayout, ZeroSizedLayout,
};
match (self, other) {
(AllocFailed(l1, c1), AllocFailed(l2, c2)) => l1 == l2 && c1 == c2,
#[cfg(feature = "fallible_dealloc")]
(AllocError::DeallocFailed(p1, l1, c1), AllocError::DeallocFailed(p2, l2, c2)) => {
p1 == p2 && l1 == l2 && c1 == c2
}
(InvalidLayout(il1), InvalidLayout(il2)) => il1 == il2,
(ZeroSizedLayout(a), ZeroSizedLayout(b)) => a == b,
(GrowSmallerNewLayout(old1, new1), GrowSmallerNewLayout(old2, new2))
| (ShrinkBiggerNewLayout(old1, new1), ShrinkBiggerNewLayout(old2, new2)) => {
old1 == old2 && new1 == new2
}
(ArithmeticOverflow(e1), ArithmeticOverflow(e2)) => e1 == e2,
(Other(a), Other(b)) => a == b,
_ => false,
}
}
}
impl Eq for AllocError {}
impl Display for AllocError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
AllocError::AllocFailed(l, cause) => {
write!(
f,
"allocation failed:\n\tlayout:\n\t\tsize: {}\n\t\talign: {}\n\tcause: {}",
l.size(),
l.align(),
cause
)
}
#[cfg(feature = "fallible_dealloc")]
AllocError::DeallocFailed(ptr, l, cause) => {
use crate::fallible_dealloc::BlockStatus;
match cause {
Cause::InvalidBlockStatus(BlockStatus::OwnedIncomplete(Some(l))) => {
write!(
f,
"deallocation failed:\n\tptr: {:p}\n\tlayout:\n\t\tsize: {}\n\t\t\
align: {}\n\tcause: ",
*ptr,
l.size(),
l.align()
)?;
write!(
f,
"owned (incomplete): full layout:\n\t\t\tsize: {}\n\t\t\talign: {}",
l.size(),
l.align()
)
}
_ => write!(
f,
"deallocation failed:\n\tptr: {:p}\n\tlayout:\n\t\tsize: {}\n\t\
\talign: {}\n\tcause: {}",
*ptr,
l.size(),
l.align(),
cause
),
}
}
AllocError::InvalidLayout(inv_layout) => {
write!(f, "{}", inv_layout)
}
AllocError::ZeroSizedLayout(_) => {
write!(f, "received a zero-sized layout")
}
AllocError::GrowSmallerNewLayout(old, new) => write!(
f,
"attempted to grow from a size of {} to a smaller size of {}",
old, new
),
AllocError::ShrinkBiggerNewLayout(old, new) => write!(
f,
"attempted to shrink from a size of {} to a larger size of {}",
old, new
),
AllocError::ArithmeticOverflow(overflow) => {
write!(f, "{}", overflow)
}
AllocError::Other(other) => write!(f, "{}", other),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for AllocError {}
#[derive(Debug)]
#[cfg_attr(not(feature = "os_err_reporting"), derive(Clone, Copy, PartialEq, Eq))]
#[repr(u8)]
pub enum Cause {
Unknown,
OutOfMemory,
#[cfg(feature = "fallible_dealloc")]
InvalidBlockStatus(crate::fallible_dealloc::BlockStatus),
#[cfg(feature = "os_err_reporting")]
OSErr(std::io::Error),
}
#[cfg(feature = "os_err_reporting")]
impl PartialEq for Cause {
fn eq(&self, other: &Cause) -> bool {
match (self, other) {
(Cause::Unknown, Cause::Unknown) | (Cause::OutOfMemory, Cause::OutOfMemory) => true,
#[cfg(feature = "fallible_dealloc")]
(Cause::InvalidBlockStatus(s1), Cause::InvalidBlockStatus(s2)) => s1 == s2,
(Cause::OSErr(e1), Cause::OSErr(e2)) => e1.kind() == e2.kind(),
_ => false,
}
}
}
impl Display for Cause {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
Cause::Unknown => write!(f, "unknown"),
Cause::OutOfMemory => write!(f, "out of memory"),
#[cfg(feature = "fallible_dealloc")]
Cause::InvalidBlockStatus(s) => write!(f, "invalid block status: {}", s),
#[cfg(feature = "os_err_reporting")]
Cause::OSErr(e) => write!(f, "os error:\n\t{}", e),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(clippy::module_name_repetitions)]
pub enum RepeatLayoutError {
InvalidLayout(InvLayout),
ArithmeticOverflow(ArithOverflow),
}
impl RepeatLayoutError {
#[must_use]
pub const fn into_alloc_err(self) -> AllocError {
match self {
RepeatLayoutError::InvalidLayout(inv_layout) => AllocError::InvalidLayout(inv_layout),
RepeatLayoutError::ArithmeticOverflow(overflow) => {
AllocError::ArithmeticOverflow(overflow)
}
}
}
}
impl Display for RepeatLayoutError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
RepeatLayoutError::InvalidLayout(inv_layout) => {
write!(f, "{}", inv_layout)
}
RepeatLayoutError::ArithmeticOverflow(overflow) => {
write!(f, "{}", overflow)
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InvLayout(pub usize, pub usize, pub LayoutErr);
impl InvLayout {
#[must_use]
pub const fn into_alloc_err(self) -> AllocError {
AllocError::InvalidLayout(self)
}
}
impl Display for InvLayout {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(
f,
"computed invalid layout:\n\tsize: {},\n\talign: {}\n\treason: {}",
self.0, self.1, self.2
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum LayoutErr {
ZeroAlign,
NonPowerOfTwoAlign,
Overflow,
}
impl Display for LayoutErr {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
LayoutErr::ZeroAlign => write!(f, "alignment is zero"),
LayoutErr::NonPowerOfTwoAlign => write!(f, "alignment is not a power of two"),
LayoutErr::Overflow => write!(f, "size would overflow"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for LayoutErr {}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ArithOverflow(pub usize, pub ArithOp, pub usize);
impl ArithOverflow {
#[must_use]
pub const fn into_alloc_err(self) -> AllocError {
AllocError::ArithmeticOverflow(self)
}
}
impl Display for ArithOverflow {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(
f,
"arithmetic operation would overflow: {} {} {}",
self.0, self.1, self.2
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for ArithOverflow {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum ArithOp {
Add,
Sub,
Mul,
Div,
Rem,
}
impl Display for ArithOp {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
ArithOp::Add => write!(f, "+"),
ArithOp::Sub => write!(f, "-"),
ArithOp::Mul => write!(f, "*"),
ArithOp::Div => write!(f, "/"),
ArithOp::Rem => write!(f, "%"),
}
}
}