use core::marker::PhantomData;
pub trait Specialize: Sized {
type Tag;
}
pub struct DefaultSpec;
pub struct InlineSpec;
pub struct NoInlineSpec;
pub struct SmallSpec;
pub struct LargeSpec;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Mono<T>(PhantomData<fn() -> T>);
impl<T> Mono<T> {
pub const fn new() -> Self {
Mono(PhantomData)
}
}
impl<T> Default for Mono<T> {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Distinct<T, const ID: u64 = 0>(PhantomData<T>);
impl<T, const ID: u64> Distinct<T, ID> {
pub const fn new() -> Self {
Distinct(PhantomData)
}
}
impl<T, const ID: u64> Default for Distinct<T, ID> {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Pure;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Stateful<S>(PhantomData<S>);
impl<S> Stateful<S> {
pub const fn new() -> Self {
Stateful(PhantomData)
}
}
impl<S> Default for Stateful<S> {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Effectful<R>(PhantomData<R>);
impl<R> Effectful<R> {
pub const fn new() -> Self {
Effectful(PhantomData)
}
}
impl<R> Default for Effectful<R> {
fn default() -> Self {
Self::new()
}
}
pub trait Fusible {
type Fused;
const FUSION_BENEFICIAL: bool = true;
}
#[derive(Debug, Clone, Copy)]
pub struct FuseWith<T>(PhantomData<T>);
impl<T> FuseWith<T> {
pub const fn new() -> Self {
FuseWith(PhantomData)
}
}
impl<T> Default for FuseWith<T> {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy)]
pub struct NoFuse;
pub struct InlineHint<F>(pub F);
impl<F> InlineHint<F> {
#[inline(always)]
pub fn new(f: F) -> Self {
InlineHint(f)
}
#[inline(always)]
pub fn call<A, R>(self, arg: A) -> R
where
F: FnOnce(A) -> R,
{
(self.0)(arg)
}
}
pub struct NoInlineHint<F>(pub F);
impl<F> NoInlineHint<F> {
#[inline(never)]
pub fn new(f: F) -> Self {
NoInlineHint(f)
}
#[inline(never)]
pub fn call<A, R>(self, arg: A) -> R
where
F: FnOnce(A) -> R,
{
(self.0)(arg)
}
}
pub trait SmallType: Sized + Copy {
const MAX_SIZE: usize = 16;
#[inline]
fn is_small() -> bool {
core::mem::size_of::<Self>() <= Self::MAX_SIZE
}
}
impl SmallType for u8 {}
impl SmallType for u16 {}
impl SmallType for u32 {}
impl SmallType for u64 {}
impl SmallType for u128 {}
impl SmallType for usize {}
impl SmallType for i8 {}
impl SmallType for i16 {}
impl SmallType for i32 {}
impl SmallType for i64 {}
impl SmallType for i128 {}
impl SmallType for isize {}
impl SmallType for f32 {}
impl SmallType for f64 {}
impl SmallType for bool {}
impl SmallType for char {}
impl<T> SmallType for *const T {}
impl<T> SmallType for *mut T {}
pub trait ZeroSized: Sized {
#[inline]
fn is_zst() -> bool {
core::mem::size_of::<Self>() == 0
}
}
impl ZeroSized for () {}
impl<T> ZeroSized for PhantomData<T> {}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "alloc")]
use alloc::string::String;
#[test]
#[cfg(feature = "alloc")]
fn test_mono_marker() {
let _m1: Mono<i32> = Mono::new();
let _m2: Mono<String> = Mono::default();
}
#[test]
#[cfg(not(feature = "alloc"))]
fn test_mono_marker() {
let _m1: Mono<i32> = Mono::new();
}
#[test]
fn test_distinct_marker() {
let _d1: Distinct<i32, 1> = Distinct::new();
let _d2: Distinct<i32, 2> = Distinct::new();
}
#[test]
fn test_effect_markers() {
let _ = Pure;
let _: Stateful<i32> = Stateful::new();
let _: Effectful<()> = Effectful::new();
}
#[test]
fn test_inline_hint() {
let hint = InlineHint::new(|x: i32| x * 2);
assert_eq!(hint.call(21), 42);
}
#[test]
fn test_no_inline_hint() {
let hint = NoInlineHint::new(|x: i32| x + 1);
assert_eq!(hint.call(41), 42);
}
#[test]
fn test_small_type() {
assert!(u32::is_small());
assert!(u64::is_small());
assert!(f64::is_small());
}
#[test]
fn test_zero_sized() {
assert!(<()>::is_zst());
assert!(<PhantomData<i32>>::is_zst());
}
}