flex_alloc/
error.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! Error handling.

use core::alloc::{Layout, LayoutError};
use core::fmt;

/// An enumeration of error types raised by storage implementations.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum StorageError {
    /// A memory allocation failed.
    AllocError(Layout),
    /// The limit of the current allocation was reached.
    CapacityLimit,
    /// The provided layout was not allocatable.
    LayoutError(LayoutError),
    /// Memory protection failed.
    ProtectionError,
    /// The requested operation is not supported for this storage.
    Unsupported,
}

impl StorageError {
    /// Generic description of this error.
    pub fn as_str(&self) -> &'static str {
        match self {
            Self::AllocError(_) => "Allocation error",
            Self::CapacityLimit => "Exceeded storage capacity limit",
            Self::LayoutError(_) => "Layout error",
            Self::ProtectionError => "Memory protection failed",
            Self::Unsupported => "Unsupported",
        }
    }

    /// Generate a panic with this error as the reason.
    #[cold]
    #[inline(never)]
    pub fn panic(self) -> ! {
        if let Self::AllocError(layout) = self {
            crate::alloc::handle_alloc_error(layout);
        } else {
            panic!("{}", self.as_str())
        }
    }
}

impl fmt::Display for StorageError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.as_str())
    }
}

impl From<LayoutError> for StorageError {
    fn from(err: LayoutError) -> Self {
        Self::LayoutError(err)
    }
}

#[cfg(feature = "std")]
impl std::error::Error for StorageError {}

/// An error raised by collection update operations when appropriate
/// storage was not available. Includes an associated value that
/// could not be stored or converted.
#[derive(Clone)]
pub struct UpdateError<T> {
    pub(crate) error: StorageError,
    pub(crate) value: T,
}

impl<T> UpdateError<T> {
    pub(crate) fn new(error: StorageError, value: T) -> Self {
        Self { error, value }
    }

    /// Generic description of this error
    pub fn as_str(&self) -> &'static str {
        "Update error"
    }

    /// Get a reference to the contained `StorageError`
    pub fn error(&self) -> &StorageError {
        &self.error
    }

    /// Unwrap the inner value of this error
    pub fn into_value(self) -> T {
        self.value
    }

    /// Generate a panic with this error as the reason
    #[cold]
    #[inline(never)]
    pub fn panic(self) -> ! {
        panic!("{}: {}", self.as_str(), self.error.as_str());
    }
}

impl<T> fmt::Debug for UpdateError<T> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("UpdateError")
            .field("error", &self.error)
            .finish_non_exhaustive()
    }
}

impl<T> fmt::Display for UpdateError<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_fmt(format_args!("{}: {}", self.as_str(), self.error))
    }
}

#[cfg(feature = "std")]
impl<T> std::error::Error for UpdateError<T> {}

#[cfg(test)]
mod tests {
    use super::StorageError;
    use core::alloc::Layout;

    #[test]
    #[should_panic(expected = "memory allocation of 8 bytes failed")]
    fn alloc_error_panic() {
        // When testing, crate::alloc::handle_alloc_error is replaced with an
        // explicit panic. This is because #[should_panic] does not currently
        // capture the panic that is started in the standard out-of-memory handler.
        let a = StorageError::AllocError(Layout::new::<usize>());
        a.panic();
    }

    #[test]
    #[should_panic(expected = "Layout error")]
    fn layout_error_panic() {
        let err = Layout::from_size_align(0, 3).expect_err("expected layout error");
        let a = StorageError::LayoutError(err);
        a.panic();
    }
}