use std::{mem, ptr};
pub trait Convention: sealed::Convention + Sized {
const TOKEN: Self;
}
impl Convention for Val {
const TOKEN: Self = Val;
}
impl Convention for Ref {
const TOKEN: Self = Ref;
}
impl Convention for Mut {
const TOKEN: Self = Mut;
}
pub trait By<'a, C: Convention> {
type Type;
fn copy(this: Self::Type) -> Self
where
Self: Copy;
fn clone(this: Self::Type) -> Self
where
Self: Clone;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Val;
impl<'a, T> By<'a, Val> for T {
type Type = T;
fn copy(this: Self::Type) -> Self
where
Self: Copy,
{
this
}
fn clone(this: Self::Type) -> Self
where
Self: Clone,
{
this
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Ref;
impl<'a, T: 'a + ?Sized> By<'a, Ref> for T {
type Type = &'a T;
fn copy(this: Self::Type) -> Self
where
Self: Copy,
{
*this
}
fn clone(this: Self::Type) -> Self
where
Self: Clone,
{
this.clone()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Mut;
impl<'a, T: 'a + ?Sized> By<'a, Mut> for T {
type Type = &'a mut T;
fn copy(this: Self::Type) -> Self
where
Self: Copy,
{
*this
}
fn clone(this: Self::Type) -> Self
where
Self: Clone,
{
this.clone()
}
}
pub trait Convert<'a, From: Convention, To: Convention>
where
Self: By<'a, To> + By<'a, From>,
{
#[allow(clippy::wrong_self_convention)]
fn convert(from: <Self as By<'a, From>>::Type) -> <Self as By<'a, To>>::Type;
}
impl<'a, T> Convert<'a, Val, Val> for T {
fn convert(from: T) -> T {
from
}
}
impl<'a, T: 'a + Clone> Convert<'a, Ref, Val> for T {
fn convert(from: &T) -> T {
from.clone()
}
}
impl<'a, T: 'a + Clone> Convert<'a, Mut, Val> for T {
fn convert(from: &mut T) -> T {
Clone::clone(from)
}
}
impl<'a, T: 'a> Convert<'a, Ref, Ref> for T {
fn convert(from: &T) -> &T {
from
}
}
impl<'a, T: 'a> Convert<'a, Mut, Ref> for T {
fn convert(from: &mut T) -> &T {
&*from
}
}
impl<'a, T: 'a> Convert<'a, Mut, Mut> for T {
fn convert(from: &mut T) -> &mut T {
from
}
}
pub trait As<'a, C: Convention, T: By<'a, C>>: By<'a, C> {
#[allow(clippy::wrong_self_convention)]
fn as_convention(this: <Self as By<'a, C>>::Type) -> <T as By<'a, C>>::Type;
}
impl<'a, T, S> As<'a, Val, T> for S
where
S: Into<T>,
{
fn as_convention(this: S) -> T {
this.into()
}
}
impl<'a, T: 'a, S: 'a> As<'a, Ref, T> for S
where
S: AsRef<T>,
{
fn as_convention(this: &S) -> &T {
this.as_ref()
}
}
impl<'a, T: 'a, S: 'a> As<'a, Mut, T> for S
where
S: AsMut<T>,
{
fn as_convention(this: &mut S) -> &mut T {
this.as_mut()
}
}
pub fn to_val<'a, T: By<'a, Val>>(by_val: T::Type) -> T {
let ptr = &by_val as *const <T as By<'a, Val>>::Type as *const T;
let val = unsafe { ptr::read(ptr) };
mem::forget(by_val); val
}
pub fn from_val<'a, T: By<'a, Val>>(by_val: T) -> T::Type {
let ptr = &by_val as *const T as *const <T as By<'a, Val>>::Type;
let val = unsafe { ptr::read(ptr) };
mem::forget(by_val); val
}
pub fn to_ref<'a, T: By<'a, Ref>>(by_ref: T::Type) -> &'a T {
let ptr = &by_ref as *const <T as By<'a, Ref>>::Type as *const &'a T;
unsafe { ptr::read(ptr) }
}
pub fn from_ref<'a, T: By<'a, Ref>>(by_ref: &'a T) -> T::Type {
let ptr = &by_ref as *const &'a T as *const <T as By<'a, Ref>>::Type;
unsafe { ptr::read(ptr) }
}
pub fn to_mut<'a, T: By<'a, Mut>>(by_mut: T::Type) -> &'a mut T {
let ptr = &by_mut as *const <T as By<'a, Mut>>::Type as *const &'a mut T;
unsafe { ptr::read(ptr) }
}
pub fn from_mut<'a, T: By<'a, Mut>>(by_mut: &'a mut T) -> T::Type {
let ptr = &by_mut as *const &'a mut T as *const <T as By<'a, Mut>>::Type;
unsafe { ptr::read(ptr) }
}
mod sealed {
use super::*;
pub trait Convention {}
impl Convention for Val {}
impl Convention for Ref {}
impl Convention for Mut {}
}