memapi2/
error.rs

1use core::{
2    alloc::Layout,
3    fmt::{Debug, Display, Formatter, Result as FmtResult},
4    ptr::NonNull
5};
6
7/// Errors for allocator operations.
8#[allow(clippy::module_name_repetitions)]
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10#[repr(u8)]
11pub enum AllocError {
12    /// The underlying allocator failed to allocate using the given layout; see the contained cause.
13    ///
14    /// The cause may or may not be accurate depending on the type and environment.
15    AllocFailed(Layout, Cause),
16    /// The layout computed with the given size and alignment is invalid; see the contained reason.
17    InvalidLayout(InvLayout),
18    /// The given alignment was invalid; see the contained information.
19    InvalidAlign(AlignErr),
20    /// The given layout was zero-sized. The contained [`NonNull`] will be dangling and valid for
21    /// the requested alignment.
22    ///
23    /// This can, in many cases, be considered a success.
24    ZeroSizedLayout(NonNull<u8>),
25    /// Attempted to grow to a smaller size.
26    GrowSmallerNewLayout(usize, usize),
27    /// Attempted to shrink to a larger size.
28    ShrinkLargerNewLayout(usize, usize),
29    /// An arithmetic error.
30    ArithmeticError(ArithErr),
31    /// Any other kind of error, in the form of a string.
32    Other(&'static str)
33}
34
35impl AllocError {
36    /// Creates a new `ArithmeticErr::Overflow` error.
37    #[allow(clippy::missing_errors_doc)]
38    #[cold]
39    #[inline(never)]
40    #[cfg_attr(not(feature = "dev"), doc(hidden))]
41    pub const fn arith_overflow(l: usize, op: ArithOp, r: usize) -> Result<usize, ArithErr> {
42        Err(ArithErr::Overflow(l, op, r))
43    }
44
45    /// Creates a new `InvLayout` error.
46    #[allow(clippy::missing_errors_doc)]
47    #[cold]
48    #[inline(never)]
49    #[cfg_attr(not(feature = "dev"), doc(hidden))]
50    pub const fn inv_layout<Ret>(
51        sz: usize,
52        align: usize,
53        err: LayoutErr
54    ) -> Result<Ret, InvLayout> {
55        Err(InvLayout(sz, align, err))
56    }
57
58    /// Creates a new `GrowSmallerNewLayout` error.
59    #[cold]
60    #[inline(never)]
61    #[cfg_attr(not(feature = "dev"), doc(hidden))]
62    #[must_use]
63    pub const fn grow_smaller(old: usize, new: usize) -> AllocError {
64        AllocError::GrowSmallerNewLayout(old, new)
65    }
66
67    /// Creates a new `ShrinkLargerNewLayout` error.
68    #[cold]
69    #[inline(never)]
70    #[cfg_attr(not(feature = "dev"), doc(hidden))]
71    #[must_use]
72    pub const fn shrink_larger(old: usize, new: usize) -> AllocError {
73        AllocError::ShrinkLargerNewLayout(old, new)
74    }
75}
76
77impl Display for AllocError {
78    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
79        use AllocError::{
80            AllocFailed,
81            ArithmeticError,
82            GrowSmallerNewLayout,
83            InvalidAlign,
84            InvalidLayout,
85            Other,
86            ShrinkLargerNewLayout,
87            ZeroSizedLayout
88        };
89
90        match self {
91            AllocFailed(l, cause) => {
92                write!(
93                    f,
94                    "allocation failed:\n\tlayout:\n\t\tsize: {}\n\t\talign: {}\n\tcause: {}",
95                    l.size(),
96                    l.align(),
97                    cause
98                )
99            }
100            InvalidLayout(inv_layout) => {
101                write!(f, "{}", inv_layout)
102            }
103            InvalidAlign(inv_align) => {
104                write!(f, "{}", inv_align)
105            }
106            ZeroSizedLayout(_) => {
107                write!(f, "received a zero-sized layout")
108            }
109            GrowSmallerNewLayout(old, new) => {
110                write!(f, "attempted to grow from a size of {} to a smaller size of {}", old, new)
111            }
112            ShrinkLargerNewLayout(old, new) => {
113                write!(f, "attempted to shrink from a size of {} to a larger size of {}", old, new)
114            }
115            ArithmeticError(overflow) => {
116                write!(f, "{}", overflow)
117            }
118            Other(other) => write!(f, "{}", other)
119        }
120    }
121}
122
123#[cfg(feature = "std")]
124impl std::error::Error for AllocError {}
125
126/// The cause of an error.
127#[derive(Debug, Copy, Clone, PartialEq, Eq)]
128#[repr(u8)]
129pub enum Cause {
130    /// The cause is unknown.
131    ///
132    /// This most commonly means an [`OSErr`](Cause::OSErr) occurred, but `os_err_reporting` is
133    /// disabled.
134    Unknown,
135    /// The allocator ran out of memory.
136    ///
137    /// This should only be used when the __allocator__ runs out of memory and doesn't grow. Use
138    /// [`OSErr`](Cause::OSErr) if the system runs out of memory.
139    OutOfMemory,
140    #[cfg(feature = "os_err_reporting")]
141    /// The cause is described in the contained OS error.
142    ///
143    /// The error may or may not be accurate depending on the environment.
144    OSErr(i32)
145}
146
147impl Display for Cause {
148    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
149        match self {
150            Cause::Unknown => write!(f, "unknown"),
151            Cause::OutOfMemory => write!(f, "out of memory"),
152            #[cfg(feature = "os_err_reporting")]
153            Cause::OSErr(e) => write!(f, "os error:\n\t{}", e)
154        }
155    }
156}
157
158#[cfg(feature = "std")]
159impl std::error::Error for Cause {}
160
161/// An invalid layout and the reason for it.
162#[derive(Debug, Clone, Copy, PartialEq, Eq)]
163pub struct InvLayout(pub usize, pub usize, pub LayoutErr);
164
165impl Display for InvLayout {
166    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
167        write!(
168            f,
169            "computed invalid layout:\n\tsize: {},\n\talign: {}\n\treason: {}",
170            self.0, self.1, self.2
171        )
172    }
173}
174
175#[cfg(feature = "std")]
176impl std::error::Error for InvLayout {}
177
178/// An error that can occur when computing a layout.
179#[derive(Debug, Clone, Copy, PartialEq, Eq)]
180#[repr(u8)]
181pub enum LayoutErr {
182    /// The alignment was invalid.
183    Align(AlignErr),
184    /// The requested size was greater than
185    /// [`USIZE_MAX_NO_HIGH_BIT`](crate::data::type_props::USIZE_MAX_NO_HIGH_BIT) when
186    /// rounded up to the nearest multiple of the requested alignment.
187    ExceedsMax,
188    /// An arithmetic error occurred.
189    ArithErr(ArithErr)
190}
191
192impl Display for LayoutErr {
193    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
194        match self {
195            LayoutErr::Align(inv_align) => write!(f, "{}", inv_align),
196            LayoutErr::ExceedsMax => write!(f, "size would overflow when rounded up to alignment"),
197            LayoutErr::ArithErr(overflow) => write!(f, "layout err: {}", overflow)
198        }
199    }
200}
201
202#[cfg(feature = "std")]
203impl std::error::Error for LayoutErr {}
204
205/// The reason for an invalid alignment.
206#[derive(Debug, Clone, Copy, PartialEq, Eq)]
207#[repr(u8)]
208pub enum AlignErr {
209    /// The alignment is zero.
210    ZeroAlign,
211    /// The alignment isn't a power of two.
212    NonPowerOfTwoAlign(usize)
213}
214
215impl Display for AlignErr {
216    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
217        match self {
218            AlignErr::ZeroAlign => write!(f, "alignment is zero"),
219            AlignErr::NonPowerOfTwoAlign(align) => {
220                write!(f, "alignment {} isn't a power of two", align)
221            }
222        }
223    }
224}
225
226#[cfg(feature = "std")]
227impl std::error::Error for AlignErr {}
228
229/// An arithmetic error.
230///
231/// Either an overflow containing the lhs, op, and rhs, or a case where the rhs is too large and
232/// that rhs value.
233#[derive(Debug, Copy, Clone, PartialEq, Eq)]
234pub enum ArithErr {
235    /// The right-hand side of the operation is too large for the operation.
236    TooLargeRhs(usize),
237    /// An overflow would occur.
238    Overflow(usize, ArithOp, usize)
239}
240
241impl Display for ArithErr {
242    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
243        match self {
244            ArithErr::TooLargeRhs(rhs) => {
245                write!(f, "right-hand side {} is too large for the operation", rhs)
246            }
247            ArithErr::Overflow(l, o, r) => {
248                write!(f, "arithmetic operation would overflow: {} {} {}", l, o, r)
249            }
250        }
251    }
252}
253
254#[cfg(feature = "std")]
255impl std::error::Error for ArithErr {}
256
257/// An arithmetic operation.
258#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
259#[repr(u8)]
260pub enum ArithOp {
261    /// Addition. (+)
262    Add,
263    /// Subtraction. (-)
264    Sub,
265    /// Multiplication. (*)
266    Mul,
267    /// Division. (/)
268    Div,
269    /// Modulo. (%)
270    Rem,
271    /// Exponentiation. (**)
272    Pow
273}
274
275impl Display for ArithOp {
276    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
277        match self {
278            ArithOp::Add => write!(f, "+"),
279            ArithOp::Sub => write!(f, "-"),
280            ArithOp::Mul => write!(f, "*"),
281            ArithOp::Div => write!(f, "/"),
282            ArithOp::Rem => write!(f, "%"),
283            ArithOp::Pow => write!(f, "**")
284        }
285    }
286}