cisness 1.1.0

Runtime 'live witness' of two types being the same
Documentation
// This uses markdown link resolution to allow links in the readme to work both on crates.io and
// within docs.rs
//! [cismute]: `cismute`
//! [live-witness]: `LiveWitness`
//! [typeid]: `core::any::TypeId`
#![doc = include_str!("../README.md")]
#![cfg_attr(not(test), no_std)]

use core::{hint::unreachable_unchecked, marker::PhantomData};

use cismute::Cismutable;

macro_rules! cisunreachable {
    () => {
        unreachable!("cismute live-witness used in code path where types were not actually the same/cismutable")
    };
}

/// Live witness type - indicates that you have for some region of code ensured that it *will not
/// actually be executed* if `U` is not the same type as `T`. If it is, then expect rapid panics.
///
/// Generally you should try to invoke this in places where it is trivially proven that the type
/// IDs of the types are already shown to be the same - this should allow the compiler to optimise
/// away basically everything.
///
/// This type attempts to expose the full power of [`cismute`] to it's users, with the caveat of
/// panicking if the types are not actually the same when the relevant transmutations are executed
/// (this should be optimised out in basically all cases, as long as you're actually doing some
/// kind of check like typeid matching to ensure the types are really the same). If you really
/// really need it, there are ways to do `unreachable_unchecked`-style transmutation.
pub struct LiveWitness<Ty, Is>(PhantomData<Ty>, PhantomData<Is>);

impl<U, T> Clone for LiveWitness<U, T> {
    #[inline(always)]
    fn clone(&self) -> Self {
        *self
    }
}
impl<U, T> Copy for LiveWitness<U, T> {}

impl<Ty, Is> LiveWitness<Ty, Is> {
    /// A live witness that says two types are the same also works in the reverse direction. This
    /// function lets you take any live witness and swap the types so you can do transmutation in
    /// the other direction
    #[inline(always)]
    pub const fn inverse(self) -> LiveWitness<Is, Ty> {
        LiveWitness::only_executed_if_same()
    }

    /// This function creates a live witness, assuring that the codepath using this type will not
    /// be invoked unless `Ty` and `Is` are the same.
    #[inline(always)]
    pub const fn only_executed_if_same() -> Self {
        Self(PhantomData, PhantomData)
    }

    /// Analogous to [`cismute::value`], but using a live witness to assure that the types are the
    /// same. This will never check at runtime if they are the same even if the compiler can't
    /// prove they are, and will cause undefined behaviour if the codepath you thought would never
    /// be executed when the types aren't the same, is actually executed when they are not the same.
    ///
    /// # Safety
    /// You must know **for certain** that this function will never be executed when `Ty` and `Is`
    /// are not the same, or this may cause highly unpredictable undefined behaviour. Prefer
    /// [`LiveWitness::value`] unless you know for sure.
    #[inline(always)]
    pub unsafe fn value_unchecked<'a, RefTy, RefIs>(&self, from: RefTy) -> RefIs
    where
        Ty: 'static,
        Is: 'static,
        RefTy: Cismutable<'a, Ty, Is, RefIs>,
    {
        match cismute::value(from) {
            Ok(v) => v,
            Err(_) => unreachable_unchecked(),
        }
    }

    /// Analogous to [`cismute::value`], but using a live witness to assure that the types are the
    /// same (panics if they are not).
    ///
    /// It may be easier on type-deduction to invoke one of several other functions that are
    /// slightly less general:
    /// * [`LiveWitness::owned`]
    /// * [`LiveWitness::reference`]
    /// * [`LiveWitness::mutable`]
    #[inline(always)]
    pub fn value<'a, RefTy, RefIs>(&self, from: RefTy) -> RefIs
    where
        Ty: 'static,
        Is: 'static,
        RefTy: Cismutable<'a, Ty, Is, RefIs>,
    {
        match cismute::value(from) {
            Ok(v) => v,
            Err(_) => {
                cisunreachable!()
            }
        }
    }

    /// Analogous to [`cismute::owned`], but using a live witness to assure that the types are the
    /// same. This will cause undefined behaviour if actually invoked when the types are not the
    /// same - consider using [`LiveWitness::owned`] if you can
    /// # Safety
    /// Ensure this is never actually invoked when the types are not the same - i.e, the codepath
    /// on which the [`LiveWitness`] is created is never run if the types are different.
    #[inline(always)]
    pub unsafe fn owned_unchecked(&self, from: Ty) -> Is
    where
        Ty: 'static,
        Is: 'static,
    {
        match cismute::owned(from) {
            Ok(v) => v,
            Err(_) => unreachable_unchecked(),
        }
    }

    /// Analogous to [`cismute::owned`], but using a live witness to assure that the types are the
    /// same. This will panic if actually invoked when the types are not the same.
    #[inline(always)]
    pub fn owned(&self, from: Ty) -> Is
    where
        Ty: 'static,
        Is: 'static,
    {
        match cismute::owned(from) {
            Ok(v) => v,
            Err(_) => cisunreachable!(),
        }
    }

    /// Analogous to [`cismute::reference`], but using a live witness to assure that the types are
    /// the same. This will cause undefined behaviour if actually invoked when the types are not
    /// the same - consider using [`LiveWitness::reference`] if you can.
    /// # Safety
    /// Ensure this is never invoked if the types are not the same
    #[inline(always)]
    pub unsafe fn reference_unchecked<'a>(&self, from: &'a Ty) -> &'a Is
    where
        Ty: 'static,
        Is: 'static,
        &'a Ty: Cismutable<'a, Ty, Is, &'a Is>,
    {
        match cismute::reference(from) {
            Ok(v) => v,
            Err(_) => unreachable_unchecked(),
        }
    }

    /// Analogous to [`cismute::reference`], but using a live witness to assure that the types are
    /// the same. This will `panic!()` if the types are not actually the same.
    #[inline(always)]
    pub fn reference<'a>(&self, from: &'a Ty) -> &'a Is
    where
        Ty: 'static,
        Is: 'static,
        &'a Ty: Cismutable<'a, Ty, Is, &'a Is>,
    {
        match cismute::reference(from) {
            Ok(v) => v,
            Err(_) => cisunreachable!(),
        }
    }

    /// Analogous to [`cismute::mutable`], but using a live witness to assure that the types are
    /// the same. This will cause undefined behaviour if actually invoked when the types are not
    /// the same - consider using [`LiveWitness::mutable`] if you can.
    /// # Safety
    /// Ensure this is never invoked if the types are not the same
    #[inline(always)]
    pub unsafe fn mutable_unchecked<'a>(&self, from: &'a mut Ty) -> &'a mut Is
    where
        Ty: 'static,
        Is: 'static,
        &'a mut Ty: Cismutable<'a, Ty, Is, &'a mut Is>,
    {
        match cismute::mutable(from) {
            Ok(v) => v,
            Err(_) => unreachable_unchecked(),
        }
    }

    /// Analogous to [`cismute::mutable`], but using a live witness to assure that the types are
    /// the same. This will `panic!()` if the types are not actually the same.
    #[inline(always)]
    pub fn mutable<'a>(&self, from: &'a mut Ty) -> &'a mut Is
    where
        Ty: 'static,
        Is: 'static,
        &'a mut Ty: Cismutable<'a, Ty, Is, &'a mut Is>,
    {
        match cismute::mutable(from) {
            Ok(v) => v,
            Err(_) => cisunreachable!(),
        }
    }
}

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.