contiguous_mem/
error.rs

1//! Errors produced by the crate.
2
3#[cfg(feature = "error_in_core")]
4use core::error::Error;
5#[cfg(all(not(feature = "error_in_core"), not(feature = "no_std")))]
6use std::error::Error;
7
8#[cfg(not(feature = "no_std"))]
9use std::sync::MutexGuard;
10#[cfg(not(feature = "no_std"))]
11use std::sync::PoisonError;
12
13use core::alloc::LayoutError;
14use core::fmt::Debug;
15#[cfg(any(not(feature = "no_std"), feature = "error_in_core"))]
16use core::fmt::{Display, Formatter, Result as FmtResult};
17
18use crate::range::ByteRange;
19
20/// Error returned when a [`Mutex`](crate::types::Mutex) or a
21/// [`RwLock`](crate::types::RwLock) isn't lockable.
22#[derive(Debug)]
23pub enum LockingError {
24    /// Not lockable because the mutex/lock was poisoned.
25    Poisoned {
26        /// Specifies source of poisoning.
27        source: LockSource,
28    },
29    /// Not lockable because the lock would be blocking.
30    WouldBlock {
31        /// Specifies which mutex/lock would block.
32        source: LockSource,
33    },
34}
35
36#[cfg(any(not(feature = "no_std"), feature = "error_in_core"))]
37impl Display for LockingError {
38    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
39        match self {
40            LockingError::Poisoned { source } => write!(
41                f,
42                "Cannot acquire lock: {}",
43                match source {
44                    LockSource::BaseAddress => {
45                        "base address Mutex was poisoned"
46                    }
47                    LockSource::AllocationTracker => "AllocationTracker Mutex was poisoned",
48                    LockSource::Reference =>
49                        "reference concurrent mutable access exclusion flag Mutex was poisoned",
50                }
51            ),
52            LockingError::WouldBlock { source } => write!(
53                f,
54                "Lock would block the current thread: {}",
55                match source {
56                    LockSource::BaseAddress => "base address already borrowed",
57                    LockSource::AllocationTracker => "AllocationTracker already borrowed",
58                    LockSource::Reference => "reference already borrowed",
59                }
60            ),
61        }
62    }
63}
64
65#[cfg(any(not(feature = "no_std"), feature = "error_in_core"))]
66impl Error for LockingError {
67    fn source(&self) -> Option<&(dyn Error + 'static)> {
68        None
69    }
70}
71
72#[cfg(not(feature = "no_std"))]
73impl From<PoisonError<MutexGuard<'_, *mut u8>>> for LockingError {
74    fn from(_: PoisonError<MutexGuard<'_, *mut u8>>) -> Self {
75        LockingError::Poisoned {
76            source: LockSource::BaseAddress,
77        }
78    }
79}
80
81#[cfg(not(feature = "no_std"))]
82impl From<PoisonError<MutexGuard<'_, crate::tracker::AllocationTracker>>> for LockingError {
83    fn from(_: PoisonError<MutexGuard<'_, crate::tracker::AllocationTracker>>) -> Self {
84        LockingError::Poisoned {
85            source: LockSource::AllocationTracker,
86        }
87    }
88}
89
90/// Error returned when concurrent mutable access is attempted to the same
91/// memory region.
92#[derive(Debug)]
93pub struct RegionBorrowedError {
94    /// [`ByteRange`] that was attempted to be borrowed.
95    pub range: ByteRange,
96}
97
98#[cfg(any(not(feature = "no_std"), feature = "error_in_core"))]
99impl Display for RegionBorrowedError {
100    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
101        write!(
102            f,
103            "attempted to borrow already mutably borrowed memory region: {}",
104            self.range
105        )
106    }
107}
108
109#[cfg(any(not(feature = "no_std"), feature = "error_in_core"))]
110impl Error for RegionBorrowedError {
111    fn source(&self) -> Option<&(dyn Error + 'static)> {
112        None
113    }
114}
115
116/// Represents errors that can occur while using the
117/// [`ContiguousMemoryStorage`](crate::ContiguousMemoryStorage) container.
118#[derive(Debug)]
119#[non_exhaustive]
120pub enum ContiguousMemoryError {
121    /// Tried to store data that does not fit into any of the remaining free
122    /// memory regions.
123    NoStorageLeft,
124    /// Attempted to occupy a memory region that is already marked as taken.
125    AlreadyUsed,
126    /// Attempted to operate on a memory region that is not contained within the
127    /// [`AllocationTracker`](crate::tracker::AllocationTracker).
128    NotContained,
129    /// Attempted to free memory that has already been deallocated.
130    DoubleFree,
131    /// The [`AllocationTracker`](crate::tracker::AllocationTracker) does not
132    /// allow shrinking to the expected size.
133    Unshrinkable {
134        /// The minimum required size to house currently stored data.
135        required_size: usize,
136    },
137    /// Indicates that a mutex wasn't lockable.
138    Lock(LockingError),
139    /// Indicates that the provided [`Layout`](core::alloc::Layout) is invalid.
140    Layout(
141        /// The underlying error that caused the [`Layout`](core::alloc::Layout)
142        /// to be considered invalid.
143        LayoutError,
144    ),
145    /// Tried mutably borrowing already borrowed region of memory
146    BorrowMut(RegionBorrowedError),
147}
148
149/// Represents possible poisoning sources for mutexes and locks.
150#[derive(Debug, Clone, Copy)]
151#[non_exhaustive]
152pub enum LockSource {
153    /// Mutex containing the base memory offset was poisoned.
154    BaseAddress,
155    /// `AllocationTracker` mutex was poisoned.
156    AllocationTracker,
157    /// Concurrent mutable access exclusion flag in `ReferenceState` was
158    /// poisoned.
159    Reference,
160}
161
162#[cfg(any(not(feature = "no_std"), feature = "error_in_core"))]
163impl Display for ContiguousMemoryError {
164    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
165        match self {
166            ContiguousMemoryError::NoStorageLeft => {
167                write!(f, "Insufficient free storage available")
168            }
169            ContiguousMemoryError::NotContained => {
170                write!(f, "Attempted to mark a memory region that isn't contained")
171            }
172            ContiguousMemoryError::AlreadyUsed => write!(
173                f,
174                "Attempted to take a memory region that is already marked as occupied"
175            ),
176            ContiguousMemoryError::DoubleFree => write!(
177                f,
178                "Attempted to free a memory region that is already marked as free"
179            ),
180            ContiguousMemoryError::Unshrinkable {
181                required_size: min_required,
182            } => write!(
183                f,
184                "Cannot shrink memory regions; minimum required space: {} bytes",
185                min_required
186            ),
187            ContiguousMemoryError::Lock(it) => write!(f, "Poison error: {}", it),
188            ContiguousMemoryError::Layout(it) => write!(f, "Layout error: {}", it),
189            ContiguousMemoryError::BorrowMut(it) => write!(f, "Borrow mutable error: {}", it),
190        }
191    }
192}
193
194#[cfg(any(not(feature = "no_std"), feature = "error_in_core"))]
195impl Error for ContiguousMemoryError {
196    fn source(&self) -> Option<&(dyn Error + 'static)> {
197        match self {
198            ContiguousMemoryError::Layout(it) => Some(it),
199            ContiguousMemoryError::Lock(it) => Some(it),
200            _ => None,
201        }
202    }
203}
204
205impl From<LockingError> for ContiguousMemoryError {
206    fn from(layout_err: LockingError) -> Self {
207        ContiguousMemoryError::Lock(layout_err)
208    }
209}
210
211impl From<LayoutError> for ContiguousMemoryError {
212    fn from(layout_err: LayoutError) -> Self {
213        ContiguousMemoryError::Layout(layout_err)
214    }
215}