use std::fmt::{Debug, Formatter};
use std::num::NonZeroU16;
use std::ops::{Bound, RangeBounds};
use crate::name_of;
#[allow(clippy::unsafe_derive_deserialize)]
#[derive(
Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd, serde::Deserialize, serde::Serialize,
)]
#[repr(transparent)]
#[serde(transparent)]
pub struct Handle(NonZeroU16);
impl Handle {
pub(crate) const MIN: Self = Self(
unsafe { NonZeroU16::new_unchecked(0x0001) },
);
pub(crate) const MAX: Self = Self(
unsafe { NonZeroU16::new_unchecked(0xFFFF) },
);
#[inline]
#[must_use]
pub(crate) const fn new(h: u16) -> Option<Self> {
match NonZeroU16::new(h) {
Some(nz) => Some(Self(nz)),
None => None,
}
}
#[inline]
pub(crate) const fn next(self) -> Option<Self> {
Self::new(self.0.get().wrapping_add(1))
}
}
impl Debug for Handle {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}({:#06X})", name_of!(Handle), self.0.get())
}
}
impl From<Handle> for u16 {
#[inline]
fn from(h: Handle) -> Self {
h.0.get()
}
}
impl From<Handle> for usize {
#[inline]
fn from(h: Handle) -> Self {
Self::from(h.0.get())
}
}
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
#[must_use]
pub struct HandleRange {
start: Handle,
end: Handle,
}
impl HandleRange {
pub const ALL: Self = Self {
start: Handle::MIN,
end: Handle::MAX,
};
#[inline]
pub const fn new(start: Handle, end: Handle) -> Self {
assert!(start.0.get() <= end.0.get());
Self { start, end }
}
#[inline(always)]
#[must_use]
pub const fn start(self) -> Handle {
self.start
}
#[inline(always)]
#[must_use]
pub const fn end(self) -> Handle {
self.end
}
}
impl RangeBounds<Handle> for HandleRange {
#[inline]
fn start_bound(&self) -> Bound<&Handle> {
Bound::Included(&self.start)
}
#[inline]
fn end_bound(&self) -> Bound<&Handle> {
Bound::Included(&self.end)
}
#[inline]
fn contains<U>(&self, item: &U) -> bool
where
Handle: PartialOrd<U>,
U: ?Sized + PartialOrd<Handle>,
{
self.start <= *item && *item <= self.end
}
}
impl Default for HandleRange {
#[inline(always)]
fn default() -> Self {
Self::ALL
}
}
impl Debug for HandleRange {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}({:#06X}..={:#06X})",
name_of!(HandleRange),
self.start.0.get(),
self.end.0.get()
)
}
}
crate::impl_display_via_debug! { Handle, HandleRange }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn handle_size() {
assert_eq!(std::mem::size_of::<Handle>(), 2);
assert_eq!(std::mem::size_of::<HandleRange>(), 4);
}
}