diff --git a/Cargo.toml b/Cargo.toml index a3da78f..db59ced 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ edition = "2018" license = "MIT" [dependencies] +const_fn = "0.4.4" serde = {version = "1.0.116", features = ["derive"], optional = true} [dev-dependencies] diff --git a/src/lib.rs b/src/lib.rs index 8977ae8..9a39c93 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,8 @@ #![cfg_attr(nightly, feature(const_fn))] #[cfg(nightly)] extern crate test; +#[macro_use] extern crate const_fn; + const MAX: usize = 256; @@ -42,8 +44,14 @@ use iter::*; pub mod entry; pub use entry::Entry; +pub mod primitive; + mod init; +mod private { + pub trait Sealed{} +} + /// A helper macro for creating `Map` instances with or without pre-set entries. /// /// # Create empty map diff --git a/src/primitive.rs b/src/primitive.rs new file mode 100644 index 0000000..834a5a9 --- /dev/null +++ b/src/primitive.rs @@ -0,0 +1,135 @@ +//! Contains `Collapse` impls for primitive types through a newtime wrapper. +//! +//! Such wrappers are a workaround for the lack of template specialisation available in Rust so far, as the generic `impl Collapse for T` still requires computing the hash of the internal types before reducing to the `u8` page index. +//! For primitive types, this is unnessisary and causes a (very slight) performance loss. +use super::*; +use std::num::*; + +pub trait PrimitiveCollapse: private::Sealed +{ + fn collapse(&self) -> u8; +} + +#[derive(Debug, Clone, PartialEq, Eq, Copy, Default, Ord, PartialOrd)] +pub struct Primitive(T); + +impl Collapse for Primitive +{ + #[inline(always)] fn collapse(&self) -> u8 { + self.0.collapse() + } +} + +impl Primitive +{ + #[const_fn] + #[inline] pub const fn new(value: T) -> Self + { + Self(value) + } + #[inline] pub fn into_inner(self) -> T + { + self.0 + } + #[const_fn] + #[inline] pub fn inner(&self) -> &T + { + &self.0 + } + #[inline] pub fn inner_mut(&mut self) -> &mut T + { + &mut self.0 + } + #[const_fn] + #[inline] pub const fn copy_into_inner(&self) -> T + where T: Copy + { + self.0 + } +} + +macro_rules! prim { + ($name:ty) => { + impl private::Sealed for $name{} + impl PrimitiveCollapse for $name + { + #[inline(always)] fn collapse(&self) -> u8 { + (*self) as u8 + } + } + }; + ($name:ty: +) => { + impl private::Sealed for $name{} + impl PrimitiveCollapse for $name + { + #[inline(always)] fn collapse(&self) -> u8 { + self.get() as u8 + } + } + }; + ($name:ty: ^) => { + impl private::Sealed for $name{} + impl PrimitiveCollapse for $name + { + #[inline(always)] fn collapse(&self) -> u8 { + super::collapse(<$name>::to_ne_bytes(*self)) + } + } + }; + ($name:ty: ^+) => { + impl private::Sealed for $name{} + impl PrimitiveCollapse for $name + { + #[inline(always)] fn collapse(&self) -> u8 { + super::collapse(self.get().to_ne_bytes()) + } + } + }; + ($name:ty: fn {$($block:tt)*}) => { + impl private::Sealed for $name{} + impl PrimitiveCollapse for $name + { + #[inline(always)] fn collapse(&self) -> u8 { + $($block)+ + } + } + }; + ($name:ty: {$($block:tt)*}) => { + impl private::Sealed for $name{} + impl PrimitiveCollapse for $name + { + $($block)+ + } + }; + +} + +prim!(u8); +prim!(i8); +prim!(u16: ^); +prim!(i16: ^); +prim!(u32: ^); +prim!(i32: ^); +prim!(u64: ^); +prim!(i64: ^); +prim!(u128: ^); +prim!(i128: ^); +prim!(isize: ^); +prim!(usize: ^); + +prim!(NonZeroU8: +); +prim!(NonZeroI8: +); +prim!(NonZeroU16: ^+); +prim!(NonZeroI16: ^+); +prim!(NonZeroU32: ^+); +prim!(NonZeroI32: ^+); +prim!(NonZeroU64: ^+); +prim!(NonZeroI64: ^+); +prim!(NonZeroU128: ^+); +prim!(NonZeroI128: ^+); +prim!(NonZeroIsize: ^+); +prim!(NonZeroUsize: ^+); + +prim!((): fn { + 0 +});