#![doc(html_root_url = "https://docs.rs/singleton-trait/0.4.0")]
#![no_std]
use core::cell::{Cell, UnsafeCell};
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
pub unsafe trait Singleton {}
unsafe impl<T: Singleton> Singleton for Cell<T> {}
unsafe impl<T: Singleton> Singleton for UnsafeCell<T> {}
unsafe impl<T: Singleton> Singleton for [T; 1] {}
unsafe impl<'a, T: Singleton> Singleton for &'a mut T {}
unsafe impl<'a, T: Singleton> Singleton for Erased<T> {}
pub unsafe trait SingleThread { }
unsafe impl<T: SingleThread> SingleThread for Cell<T> {}
unsafe impl<T: SingleThread> SingleThread for [T; 1] {}
unsafe impl<'a, T: SingleThread> SingleThread for &'a mut T {}
unsafe impl<'a, T: SingleThread> SingleThread for &'a T {}
unsafe impl<'a, T: SingleThread> SingleThread for Erased<T> {}
#[derive(Copy)]
pub struct Erased<T> {
_phantom: PhantomData<ManuallyDrop<T>>,
}
impl<T: Copy> Clone for Erased<T> {
#[inline(always)]
fn clone(&self) -> Self {
*self
}
}
impl<T> Erased<T> {
#[inline(always)]
pub const fn new(t: T) -> Self {
let _ = ManuallyDrop::new(t);
unsafe { Self::new_unchecked() }
}
#[inline(always)]
pub const unsafe fn new_unchecked() -> Self {
Erased {
_phantom: PhantomData,
}
}
#[inline(always)]
pub fn borrow(&self) -> Erased<&T> {
unsafe { self.map_borrow(|r| r) }
}
#[inline(always)]
pub fn borrow_mut(&mut self) -> Erased<&mut T> {
unsafe { self.map_borrow_mut(|r| r) }
}
#[inline(always)]
pub unsafe fn map<R, F: FnOnce(T) -> R>(self, _: impl Exists<F>) -> Erased<R> {
Erased::<R>::new_unchecked()
}
#[inline(always)]
pub unsafe fn map_borrow<'a, R, F: FnOnce(&'a T) -> R>(
&'a self,
_: impl Exists<F>,
) -> Erased<R> {
Erased::<R>::new_unchecked()
}
#[inline(always)]
pub unsafe fn map_borrow_mut<'a, R, F: FnOnce(&'a mut T) -> R>(
&'a mut self,
_: impl Exists<F>,
) -> Erased<R> {
Erased::<R>::new_unchecked()
}
#[inline(always)]
pub fn exists(self) -> impl Exists<T> {
struct Internal<T> {
er: Erased<T>,
}
impl<T> Exists<T> for Internal<T> {
#[inline(always)]
fn erase(self) -> Erased<T> {
self.er
}
}
Internal { er: self }
}
}
impl<T> Erased<Erased<T>> {
#[inline(always)]
pub fn flatten(self) -> Erased<T> {
unsafe { Erased::<T>::new_unchecked() }
}
}
impl<'a, T> Erased<&'a mut T> {
#[inline(always)]
pub fn reborrow<'b>(&'b mut self) -> Erased<&'b mut T> {
unsafe { self.map_borrow_mut(|r: &'b mut &'a mut T| &mut **r) }
}
#[inline(always)]
pub fn read<'b>(&'b self) -> Erased<&'b T> {
unsafe { self.map_borrow(|r: &'b &'a mut T| &**r) }
}
#[inline(always)]
pub fn into_shared(self) -> Erased<&'a T> {
unsafe { self.map(|r: &'a mut T| &*r) }
}
}
impl<T> From<T> for Erased<T> {
#[inline(always)]
fn from(t: T) -> Self {
Self::new(t)
}
}
pub trait Exists<T: Sized> {
fn erase(self) -> Erased<T>;
}
impl<T> Exists<T> for T {
#[inline(always)]
fn erase(self) -> Erased<T> {
self.into()
}
}
impl<'a, 'b: 'a, T> Exists<&'a T> for Erased<&'b T> {
#[inline(always)]
fn erase(self) -> Erased<&'a T> {
self
}
}
impl<'a, 'b: 'a, T> Exists<&'a T> for Erased<&'b mut T> {
#[inline(always)]
fn erase(self) -> Erased<&'a T> {
self.into_shared()
}
}
impl<'a, 'b: 'a, T> Exists<&'a mut T> for Erased<&'b mut T> {
#[inline(always)]
fn erase(self) -> Erased<&'a mut T> {
unsafe { self.map(|r: &'a mut T| &mut *r) }
}
}
impl<'a, 'b, T> Exists<&'a T> for &'a Erased<&'b T> {
#[inline(always)]
fn erase(self) -> Erased<&'a T> {
*self
}
}
impl<'a, 'b: 'a, T> Exists<&'a T> for &'a Erased<&'b mut T> {
#[inline(always)]
fn erase(self) -> Erased<&'a T> {
self.read()
}
}
impl<'a, 'b: 'a, T> Exists<&'a mut T> for &'a mut Erased<&'b mut T> {
#[inline(always)]
fn erase(self) -> Erased<&'a mut T> {
self.reborrow()
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn test_impls() {
struct NonCopy;
impl Drop for NonCopy {
fn drop(&mut self) {}
}
struct Guard<'a>(PhantomData<fn(&'a ()) -> &'a ()>, &'a NonCopy);
fn takes_ref<'a>(_: &Guard<'a>, _: impl Exists<&'a ()>) {}
fn takes_mut<'a>(_: &Guard<'a>, _: impl Exists<&'a mut ()>) {}
let nc = NonCopy;
let guard = Guard(PhantomData, &nc);
let er = Erased::new(&());
takes_ref(&guard, er);
let mut x = ();
let er = Erased::new(&mut x);
takes_ref(&guard, er);
let mut x = ();
let er = Erased::new(&mut x);
takes_mut(&guard, er);
}
}