use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::ops::Range;
use pi_result::{ClassifyErrorKind, ErrorKind, RawResult};
#[derive(Debug, pi_result::thiserror::Error)]
#[non_exhaustive]
pub enum MmapRangeError {
#[error("mmap range is empty at byte offset {at}")]
Empty {
at: u64,
},
#[error("mmap range is reversed: start {start} exceeds end {end_exclusive}")]
Reversed {
start: u64,
end_exclusive: u64,
},
}
impl ClassifyErrorKind for MmapRangeError {
fn classify_error_kind(&self) -> ErrorKind {
ErrorKind::InvalidInput
}
}
pub struct MmapRange {
start: u64,
end_exclusive: u64,
}
impl MmapRange {
pub fn new(start: u64, end_exclusive: u64) -> RawResult<Self, MmapRangeError> {
match start.cmp(&end_exclusive) {
Ordering::Less => Ok(Self {
start,
end_exclusive,
}),
Ordering::Equal => Err(MmapRangeError::Empty { at: start }),
Ordering::Greater => Err(MmapRangeError::Reversed {
start,
end_exclusive,
}),
}
}
#[must_use]
pub fn start(&self) -> u64 {
self.start
}
#[must_use]
pub fn end_exclusive(&self) -> u64 {
self.end_exclusive
}
#[must_use]
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> u64 {
self.end_exclusive - self.start
}
}
impl fmt::Debug for MmapRange {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("MmapRange")
.field("start", &self.start)
.field("end_exclusive", &self.end_exclusive)
.finish()
}
}
impl fmt::Display for MmapRange {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "[{}, {})", self.start, self.end_exclusive)
}
}
impl PartialEq for MmapRange {
fn eq(&self, other: &Self) -> bool {
self.start == other.start && self.end_exclusive == other.end_exclusive
}
}
impl Eq for MmapRange {}
impl PartialOrd for MmapRange {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for MmapRange {
fn cmp(&self, other: &Self) -> Ordering {
self.start
.cmp(&other.start)
.then_with(|| self.end_exclusive.cmp(&other.end_exclusive))
}
}
impl Hash for MmapRange {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.start.hash(state);
self.end_exclusive.hash(state);
}
}
impl TryFrom<Range<u64>> for MmapRange {
type Error = MmapRangeError;
fn try_from(range: Range<u64>) -> Result<Self, Self::Error> {
Self::new(range.start, range.end)
}
}