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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
//! Errors produced by the crate.

#[cfg(all(feature = "error_in_core"))]
use core::error::Error;
#[cfg(all(not(feature = "error_in_core"), feature = "std"))]
use std::error::Error;

#[cfg(feature = "std")]
use std::sync::MutexGuard;
#[cfg(feature = "std")]
use std::sync::PoisonError;

use core::alloc::LayoutError;
use core::fmt::Debug;
#[cfg(any(feature = "std", feature = "error_in_core"))]
use core::fmt::{Display, Formatter, Result as FmtResult};

use crate::range::ByteRange;

/// Error returned when a [`Mutex`](crate::types::Mutex) or a
/// [`RwLock`](crate::types::RwLock) isn't lockable.
#[derive(Debug)]
pub enum LockingError {
    /// Not lockable because the mutex/lock was poisoned.
    Poisoned {
        /// Specifies source of poisoning.
        source: LockSource,
    },
    /// Not lockable because the lock would be blocking.
    WouldBlock,
}

#[cfg(any(feature = "std", feature = "error_in_core"))]
impl Display for LockingError {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        match self {
            LockingError::Poisoned { source: which } => match which {
                LockSource::BaseAddress => {
                    write!(f, "Cannot acquire lock: base address Mutex was poisoned")
                }
                LockSource::AllocationTracker => write!(
                    f,
                    "Cannot acquire lock: AllocationTracker Mutex was poisoned"
                ),
                LockSource::Reference => write!(
                    f,
                    "Cannot acquire lock: reference concurrent mutable access exclusion flag Mutex was poisoned"
                )
            },
            LockingError::WouldBlock => write!(f, "Lock would be block"),
        }
    }
}

#[cfg(any(feature = "std", feature = "error_in_core"))]
impl Error for LockingError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        None
    }
}

#[cfg(feature = "std")]
impl From<PoisonError<MutexGuard<'_, *mut u8>>> for LockingError {
    fn from(_: PoisonError<MutexGuard<'_, *mut u8>>) -> Self {
        LockingError::Poisoned {
            source: LockSource::BaseAddress,
        }
    }
}

#[cfg(feature = "std")]
impl From<PoisonError<MutexGuard<'_, crate::tracker::AllocationTracker>>> for LockingError {
    fn from(_: PoisonError<MutexGuard<'_, crate::tracker::AllocationTracker>>) -> Self {
        LockingError::Poisoned {
            source: LockSource::AllocationTracker,
        }
    }
}

#[cfg(feature = "std")]
impl<T> From<std::sync::TryLockError<T>> for LockingError
where
    LockingError: From<PoisonError<T>>,
{
    fn from(value: std::sync::TryLockError<T>) -> Self {
        match value {
            std::sync::TryLockError::Poisoned(poison_err) => LockingError::from(poison_err),
            std::sync::TryLockError::WouldBlock => LockingError::WouldBlock,
        }
    }
}

/// Error returned when concurrent mutable access is attempted to the same
/// memory region.
#[derive(Debug)]
pub struct RegionBorrowed {
    /// [`ByteRange`] that was attempted to be borrowed.
    pub range: ByteRange,
}

#[cfg(any(feature = "std", feature = "error_in_core"))]
impl Display for RegionBorrowed {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        write!(
            f,
            "attempted to borrow already mutably borrowed memory region: {}",
            self.range
        )
    }
}

#[cfg(any(feature = "std", feature = "error_in_core"))]
impl Error for RegionBorrowed {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        None
    }
}

/// Represents errors that can occur while using the
/// [`ContiguousMemoryStorage`](crate::ContiguousMemoryStorage) container.
#[derive(Debug)]
#[non_exhaustive]
pub enum ContiguousMemoryError {
    /// Tried to store data that does not fit into any of the remaining free
    /// memory regions.
    NoStorageLeft,
    /// Attempted to occupy a memory region that is already marked as taken.
    AlreadyUsed,
    /// Attempted to operate on a memory region that is not contained within the
    /// [`AllocationTracker`](crate::tracker::AllocationTracker).
    NotContained,
    /// Attempted to free memory that has already been deallocated.
    DoubleFree,
    /// The [`AllocationTracker`](crate::tracker::AllocationTracker) does not
    /// allow shrinking to the expected size.
    Unshrinkable {
        /// The minimum required size to house currently stored data.
        required_size: usize,
    },
    /// Indicates that a mutex wasn't lockable.
    Lock(LockingError),
    /// Attempted to borrow the
    /// [`AllocationTracker`](crate::tracker::AllocationTracker) which is
    /// already in use.
    TrackerInUse,
    /// Indicates that the provided [`Layout`](core::alloc::Layout) is invalid.
    Layout(
        /// The underlying error that caused the [`Layout`](core::alloc::Layout)
        /// to be considered invalid.
        LayoutError,
    ),
    /// Tried mutably borrowing already borrowed region of memory
    BorrowMut(RegionBorrowed),
}

/// Represents possible poisoning sources for mutexes and locks.
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub enum LockSource {
    /// Mutex containing the base memory offset was poisoned.
    BaseAddress,
    /// [`AllocationTracker`](crate::tracker::AllocationTracker) mutex was
    /// poisoned.
    AllocationTracker,
    /// Concurrent mutable access exclusion flag in
    /// [`ReferenceState`](crate::refs) was poisoned.
    Reference,
}

#[cfg(any(feature = "std", feature = "error_in_core"))]
impl Display for ContiguousMemoryError {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        match self {
            ContiguousMemoryError::NoStorageLeft => {
                write!(f, "Insufficient free storage available")
            }
            ContiguousMemoryError::NotContained => {
                write!(f, "Attempted to mark a memory region that isn't contained")
            }
            ContiguousMemoryError::AlreadyUsed => write!(
                f,
                "Attempted to take a memory region that is already marked as occupied"
            ),
            ContiguousMemoryError::DoubleFree => write!(
                f,
                "Attempted to free a memory region that is already marked as free"
            ),
            ContiguousMemoryError::Unshrinkable {
                required_size: min_required,
            } => write!(
                f,
                "Cannot shrink memory regions; minimum required space: {} bytes",
                min_required
            ),
            ContiguousMemoryError::Lock(it) => write!(f, "Poison error: {}", it),
            ContiguousMemoryError::TrackerInUse => {
                write!(f, "Cannot borrow AllocationTracker: it is already in use")
            }
            ContiguousMemoryError::Layout(it) => write!(f, "Layout error: {}", it),
            ContiguousMemoryError::BorrowMut(it) => write!(f, "Borrow mutable error: {}", it),
        }
    }
}

#[cfg(any(feature = "std", feature = "error_in_core"))]
impl Error for ContiguousMemoryError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match self {
            ContiguousMemoryError::Layout(it) => Some(it),
            ContiguousMemoryError::Lock(it) => Some(it),
            _ => None,
        }
    }
}

impl From<LockingError> for ContiguousMemoryError {
    fn from(layout_err: LockingError) -> Self {
        ContiguousMemoryError::Lock(layout_err)
    }
}

impl From<LayoutError> for ContiguousMemoryError {
    fn from(layout_err: LayoutError) -> Self {
        ContiguousMemoryError::Layout(layout_err)
    }
}