use crate::any::{Any, TypeId};
use crate::transience::Transience;
pub unsafe trait Transient: Sized {
type Static: 'static;
type Transience: Transience;
#[doc(hidden)]
const CHECK: () = check_static_type::<Self>();
#[inline]
fn static_type_id(&self) -> TypeId {
TypeId::of::<Self>()
}
#[inline]
fn erase<'a>(self: Box<Self>) -> Box<dyn Any<Self::Transience> + 'a>
where
Self: 'a,
{
let () = Self::CHECK;
self
}
#[inline]
fn erase_ref<'a>(&self) -> &(dyn Any<Self::Transience> + 'a)
where
Self: 'a,
{
let () = Self::CHECK;
self
}
#[inline]
fn erase_mut<'a>(&mut self) -> &mut (dyn Any<Self::Transience> + 'a)
where
Self: 'a,
{
let () = Self::CHECK;
self
}
}
pub trait Static: 'static + Sized {}
unsafe impl<S: Static> Transient for S {
type Static = Self;
type Transience = ();
}
#[track_caller]
const fn check_static_type<T: Transient>() {
use std::alloc::Layout;
use std::mem::size_of;
assert!(
size_of::<T>() == size_of::<T::Static>(),
"Size mismatch! `T::Static` should be the same as `T` \
but with its lifetimes replaced by `'static`"
);
assert!(
Layout::new::<T>().align() == Layout::new::<T::Static>().align(),
"Alignment mismatch! `T::Static` should be the same as `T` \
but with its lifetimes replaced by `'static`"
);
}
mod std_impls {
#![allow(unused_parens)]
use super::{Static, Transient};
use crate::{Co, Contravariant, Covariant, Inv, Invariant};
macro_rules! impl_refs {
{
$type_:ty
[$($param:tt $(: $bound1:tt $(+ $bounds:tt)*)?),*]
$( ($($trans:ty),+) )?
} => {
unsafe impl<'_a, $( $param $( : $bound1 $(+ $bounds )* )? ),*>
Transient for &'_a $type_ {
type Static = &'static <$type_ as Transient>::Static;
type Transience = (Co<'_a> $($(, $trans)+)?);
}
unsafe impl<'_a, $( $param $( : $bound1 $(+ $bounds )* )? ),*>
Transient for &'_a mut $type_ {
type Static = &'static mut <$type_ as Transient>::Static;
type Transience = (Co<'_a> $($(, $trans)+)?);
}
unsafe impl<'_a, '_b, $( $param $( : $bound1 $(+ $bounds )* )? ),*>
Transient for &'_a &'_b $type_ {
type Static = &'static &'static <$type_ as Transient>::Static;
type Transience = (Co<'_a>, Co<'_b> $($(, $trans)+)?);
}
unsafe impl<'_a, '_b, $( $param $( : $bound1 $(+ $bounds )* )? ),*>
Transient for &'_a mut &'_b $type_ {
type Static = &'static mut &'static <$type_ as Transient>::Static;
type Transience = (Co<'_a>, Inv<'_b> $($(, $trans)+)?);
}
unsafe impl<'_a, '_b, $( $param $( : $bound1 $(+ $bounds )* )? ),*>
Transient for &'_a &'_b mut $type_ {
type Static = &'static &'static mut <$type_ as Transient>::Static;
type Transience = (Co<'_a>, Co<'_b> $($(, $trans)+)?);
}
unsafe impl<'_a, '_b, $( $param $( : $bound1 $(+ $bounds )* )? ),*>
Transient for &'_a mut &'_b mut $type_ {
type Static = &'static mut &'static <$type_ as Transient>::Static;
type Transience = (Co<'_a>, Inv<'_b> $($(, $trans)+)?);
}
}
}
macro_rules! impl_static {
( $($ty:ty),* $(,)? ) => {
$(
impl Static for $ty {}
impl_refs!($ty []);
)*
}
}
impl_static! {
isize, i8, i16, i32, i64, i128,
usize, u8, u16, u32, u64, u128,
f32, f64, String, Box<str>, (),
std::char::ParseCharError,
std::char::DecodeUtf16Error,
std::convert::Infallible,
std::num::ParseIntError,
std::num::ParseFloatError,
std::num::IntErrorKind,
std::num::TryFromIntError,
std::str::ParseBoolError,
std::str::Utf8Error,
std::string::FromUtf8Error,
std::string::FromUtf16Error,
std::net::AddrParseError,
std::io::Error,
std::io::ErrorKind,
std::fmt::Error,
std::env::VarError,
std::env::JoinPathsError,
std::time::SystemTimeError,
}
unsafe impl<'a> Transient for &'a str {
type Static = &'static str;
type Transience = Co<'a>;
}
impl_refs!(&'a str ['a]);
unsafe impl<'a> Transient for &'a mut str {
type Static = &'static mut str;
type Transience = Co<'a>;
}
impl_refs!(&'a mut str ['a]);
unsafe impl<'a, T: Transient> Transient for &'a [T] {
type Static = &'static [T::Static];
type Transience = (Co<'a>, Covariant<T>);
}
impl_refs!(&'a [T] ['a, T: Transient] (Co<'a>, Covariant<T>));
unsafe impl<'a, T: Transient> Transient for &'a mut [T] {
type Static = &'static mut [T::Static];
type Transience = (Co<'a>, Invariant<T>);
}
impl_refs!(&'a mut [T] ['a, T: Transient] (Co<'a>, Invariant<T>));
unsafe impl<T: Transient> Transient for Vec<T> {
type Static = Vec<T::Static>;
type Transience = Covariant<T>;
}
impl_refs!(Vec<T> [T: Transient] (Covariant<T>));
unsafe impl<K: Transient, V: Transient> Transient for std::collections::HashMap<K, V> {
type Static = std::collections::HashMap<K::Static, V::Static>;
type Transience = (Covariant<K>, Covariant<V>);
}
impl_refs!(
std::collections::HashMap<K, V>
[K: Transient, V: Transient]
(Covariant<K>, Covariant<V>)
);
unsafe impl<T: Transient> Transient for Box<[T]> {
type Static = Box<[T::Static]>;
type Transience = Covariant<T>;
}
unsafe impl<'a, T> Transient for std::borrow::Cow<'a, T>
where
T: Transient + std::borrow::ToOwned,
T::Static: std::borrow::ToOwned,
{
type Static = std::borrow::Cow<'static, T::Static>;
type Transience = (Co<'a>, Covariant<T>);
}
unsafe impl<T: Transient> Transient for Option<T> {
type Static = Option<T::Static>;
type Transience = Covariant<T>;
}
unsafe impl<T: Transient, E: 'static> Transient for Result<T, E> {
type Static = Result<T::Static, E>;
type Transience = Covariant<T>;
}
unsafe impl<T: Transient> Transient for std::marker::PhantomData<T> {
type Static = std::marker::PhantomData<T::Static>;
type Transience = Covariant<T>;
}
unsafe impl<T: Transient> Transient for std::cell::Cell<T> {
type Static = std::marker::PhantomData<T::Static>;
type Transience = Invariant<T>;
}
unsafe impl<T: Transient> Transient for *const T {
type Static = *const T::Static;
type Transience = Covariant<T>;
}
unsafe impl<T: Transient> Transient for *mut T {
type Static = *mut T::Static;
type Transience = Invariant<T>;
}
unsafe impl<T: Transient> Transient for std::ptr::NonNull<T> {
type Static = std::ptr::NonNull<T::Static>;
type Transience = Covariant<T>;
}
impl Static for Box<dyn std::any::Any> {}
unsafe impl<'a> Transient for &'a dyn std::any::Any {
type Static = &'static dyn std::any::Any;
type Transience = Co<'a>;
}
unsafe impl<'a> Transient for &'a mut dyn std::any::Any {
type Static = &'static mut dyn std::any::Any;
type Transience = Co<'a>;
}
macro_rules! impl_fn_pointers {
{ $( ($($In:ident),*) ),* } => {
$(
unsafe impl<$($In,)* Out> Transient for fn($($In),*) -> Out
where
$($In: Transient,)*
Out: Transient,
{
type Static = fn($($In::Static),*) -> Out::Static;
type Transience = ($(Contravariant<$In>,)* Covariant<Out>);
}
)*
};
}
impl_fn_pointers! {
(), (In1), (In1, In2), (In1, In2, In3), (In1, In2, In3, In4)
}
}
#[cfg(feature = "ndarray")]
mod ndarray_impls {
use ndarray::{ArcArray, Array, ArrayView, ArrayViewMut, CowArray, Dimension};
impl<T: 'static, D: Dimension + 'static> crate::Static for Array<T, D> {}
unsafe impl<'a, T, D> crate::Transient for ArrayView<'a, T, D>
where
T: 'static,
D: Dimension + 'static,
{
type Static = ArrayView<'static, T, D>;
type Transience = crate::Co<'a>;
}
unsafe impl<'a, T, D> crate::Transient for ArrayViewMut<'a, T, D>
where
T: 'static,
D: Dimension + 'static,
{
type Static = ArrayViewMut<'static, T, D>;
type Transience = crate::Co<'a>;
}
unsafe impl<T, D> crate::Transient for ArcArray<T, D>
where
T: 'static,
D: Dimension + 'static,
{
type Static = ArcArray<T, D>;
type Transience = ();
}
unsafe impl<'a, T, D> crate::Transient for CowArray<'a, T, D>
where
T: 'static,
D: Dimension + 'static,
{
type Static = CowArray<'static, T, D>;
type Transience = crate::Co<'a>;
}
}
#[cfg(feature = "pyo3")]
mod pyo3_impls {
use crate::{tr::Transient, Co, Static};
use pyo3::pyclass::{boolean_struct::False, PyClass};
use pyo3::{Borrowed, Bound, Py, PyErr, PyRef, PyRefMut};
impl<T: 'static> Static for Py<T> {}
unsafe impl<'py, T: 'static> Transient for Bound<'py, T> {
type Static = Bound<'static, T>;
type Transience = Co<'py>;
}
unsafe impl<'a, 'py, T: 'static> Transient for Borrowed<'a, 'py, T> {
type Static = Borrowed<'static, 'static, T>;
type Transience = (Co<'a>, Co<'py>);
}
unsafe impl<'py, T: PyClass> Transient for PyRef<'py, T> {
type Static = PyRef<'static, T>;
type Transience = Co<'py>;
}
unsafe impl<'py, T: PyClass<Frozen = False>> Transient for PyRefMut<'py, T> {
type Static = PyRefMut<'static, T>;
type Transience = Co<'py>;
}
impl Static for PyErr {}
}
#[cfg(feature = "numpy")]
mod numpy_impls {
use numpy::ndarray::Dimension;
use numpy::{Element, PyReadonlyArray, PyReadwriteArray};
unsafe impl<'py, T, D> crate::Transient for PyReadonlyArray<'py, T, D>
where
T: Element + 'static,
D: Dimension + 'static,
{
type Static = PyReadonlyArray<'static, T, D>;
type Transience = crate::Co<'py>;
}
unsafe impl<'py, T, D> crate::Transient for PyReadwriteArray<'py, T, D>
where
T: Element + 'static,
D: Dimension + 'static,
{
type Static = PyReadwriteArray<'static, T, D>;
type Transience = crate::Co<'py>;
}
}
#[cfg(feature = "uuid")]
mod uuid_impls {
use super::Static;
use uuid::*;
impl Static for Uuid {}
impl Static for Error {}
impl Static for Variant {}
impl Static for Version {}
}
#[cfg(feature = "either")]
mod either_impls {
use crate::Covariant;
use either::Either;
unsafe impl<L, R> crate::Transient for Either<L, R>
where
L: crate::Transient,
R: crate::Transient,
{
type Static = Either<L::Static, R::Static>;
type Transience = (Covariant<L>, Covariant<R>);
}
}
#[cfg(feature = "serde_json")]
mod serde_json_impls {
use serde_json::Error;
impl crate::Static for Error {}
}
#[cfg(feature = "rmp-serde")]
mod rmp_serde_impls {
use rmp_serde::{decode, encode};
impl crate::Static for encode::Error {}
impl crate::Static for decode::Error {}
}