cisness/lib.rs
1// This uses markdown link resolution to allow links in the readme to work both on crates.io and
2// within docs.rs
3//! [cismute]: `cismute`
4//! [live-witness]: `LiveWitness`
5//! [typeid]: `core::any::TypeId`
6#![doc = include_str!("../README.md")]
7#![cfg_attr(not(test), no_std)]
8
9use core::{hint::unreachable_unchecked, marker::PhantomData};
10
11use cismute::Cismutable;
12
13macro_rules! cisunreachable {
14 () => {
15 unreachable!("cismute live-witness used in code path where types were not actually the same/cismutable")
16 };
17}
18
19/// Live witness type - indicates that you have for some region of code ensured that it *will not
20/// actually be executed* if `U` is not the same type as `T`. If it is, then expect rapid panics.
21///
22/// Generally you should try to invoke this in places where it is trivially proven that the type
23/// IDs of the types are already shown to be the same - this should allow the compiler to optimise
24/// away basically everything.
25///
26/// This type attempts to expose the full power of [`cismute`] to it's users, with the caveat of
27/// panicking if the types are not actually the same when the relevant transmutations are executed
28/// (this should be optimised out in basically all cases, as long as you're actually doing some
29/// kind of check like typeid matching to ensure the types are really the same). If you really
30/// really need it, there are ways to do `unreachable_unchecked`-style transmutation.
31pub struct LiveWitness<Ty, Is>(PhantomData<Ty>, PhantomData<Is>);
32
33impl<U, T> Clone for LiveWitness<U, T> {
34 #[inline(always)]
35 fn clone(&self) -> Self {
36 *self
37 }
38}
39impl<U, T> Copy for LiveWitness<U, T> {}
40
41impl<Ty, Is> LiveWitness<Ty, Is> {
42 /// A live witness that says two types are the same also works in the reverse direction. This
43 /// function lets you take any live witness and swap the types so you can do transmutation in
44 /// the other direction
45 #[inline(always)]
46 pub const fn inverse(self) -> LiveWitness<Is, Ty> {
47 LiveWitness::only_executed_if_same()
48 }
49
50 /// This function creates a live witness, assuring that the codepath using this type will not
51 /// be invoked unless `Ty` and `Is` are the same.
52 #[inline(always)]
53 pub const fn only_executed_if_same() -> Self {
54 Self(PhantomData, PhantomData)
55 }
56
57 /// Analogous to [`cismute::value`], but using a live witness to assure that the types are the
58 /// same. This will never check at runtime if they are the same even if the compiler can't
59 /// prove they are, and will cause undefined behaviour if the codepath you thought would never
60 /// be executed when the types aren't the same, is actually executed when they are not the same.
61 ///
62 /// # Safety
63 /// You must know **for certain** that this function will never be executed when `Ty` and `Is`
64 /// are not the same, or this may cause highly unpredictable undefined behaviour. Prefer
65 /// [`LiveWitness::value`] unless you know for sure.
66 #[inline(always)]
67 pub unsafe fn value_unchecked<'a, RefTy, RefIs>(&self, from: RefTy) -> RefIs
68 where
69 Ty: 'static,
70 Is: 'static,
71 RefTy: Cismutable<'a, Ty, Is, RefIs>,
72 {
73 match cismute::value(from) {
74 Ok(v) => v,
75 Err(_) => unreachable_unchecked(),
76 }
77 }
78
79 /// Analogous to [`cismute::value`], but using a live witness to assure that the types are the
80 /// same (panics if they are not).
81 ///
82 /// It may be easier on type-deduction to invoke one of several other functions that are
83 /// slightly less general:
84 /// * [`LiveWitness::owned`]
85 /// * [`LiveWitness::reference`]
86 /// * [`LiveWitness::mutable`]
87 #[inline(always)]
88 pub fn value<'a, RefTy, RefIs>(&self, from: RefTy) -> RefIs
89 where
90 Ty: 'static,
91 Is: 'static,
92 RefTy: Cismutable<'a, Ty, Is, RefIs>,
93 {
94 match cismute::value(from) {
95 Ok(v) => v,
96 Err(_) => {
97 cisunreachable!()
98 }
99 }
100 }
101
102 /// Analogous to [`cismute::owned`], but using a live witness to assure that the types are the
103 /// same. This will cause undefined behaviour if actually invoked when the types are not the
104 /// same - consider using [`LiveWitness::owned`] if you can
105 /// # Safety
106 /// Ensure this is never actually invoked when the types are not the same - i.e, the codepath
107 /// on which the [`LiveWitness`] is created is never run if the types are different.
108 #[inline(always)]
109 pub unsafe fn owned_unchecked(&self, from: Ty) -> Is
110 where
111 Ty: 'static,
112 Is: 'static,
113 {
114 match cismute::owned(from) {
115 Ok(v) => v,
116 Err(_) => unreachable_unchecked(),
117 }
118 }
119
120 /// Analogous to [`cismute::owned`], but using a live witness to assure that the types are the
121 /// same. This will panic if actually invoked when the types are not the same.
122 #[inline(always)]
123 pub fn owned(&self, from: Ty) -> Is
124 where
125 Ty: 'static,
126 Is: 'static,
127 {
128 match cismute::owned(from) {
129 Ok(v) => v,
130 Err(_) => cisunreachable!(),
131 }
132 }
133
134 /// Analogous to [`cismute::reference`], but using a live witness to assure that the types are
135 /// the same. This will cause undefined behaviour if actually invoked when the types are not
136 /// the same - consider using [`LiveWitness::reference`] if you can.
137 /// # Safety
138 /// Ensure this is never invoked if the types are not the same
139 #[inline(always)]
140 pub unsafe fn reference_unchecked<'a>(&self, from: &'a Ty) -> &'a Is
141 where
142 Ty: 'static,
143 Is: 'static,
144 &'a Ty: Cismutable<'a, Ty, Is, &'a Is>,
145 {
146 match cismute::reference(from) {
147 Ok(v) => v,
148 Err(_) => unreachable_unchecked(),
149 }
150 }
151
152 /// Analogous to [`cismute::reference`], but using a live witness to assure that the types are
153 /// the same. This will `panic!()` if the types are not actually the same.
154 #[inline(always)]
155 pub fn reference<'a>(&self, from: &'a Ty) -> &'a Is
156 where
157 Ty: 'static,
158 Is: 'static,
159 &'a Ty: Cismutable<'a, Ty, Is, &'a Is>,
160 {
161 match cismute::reference(from) {
162 Ok(v) => v,
163 Err(_) => cisunreachable!(),
164 }
165 }
166
167 /// Analogous to [`cismute::mutable`], but using a live witness to assure that the types are
168 /// the same. This will cause undefined behaviour if actually invoked when the types are not
169 /// the same - consider using [`LiveWitness::mutable`] if you can.
170 /// # Safety
171 /// Ensure this is never invoked if the types are not the same
172 #[inline(always)]
173 pub unsafe fn mutable_unchecked<'a>(&self, from: &'a mut Ty) -> &'a mut Is
174 where
175 Ty: 'static,
176 Is: 'static,
177 &'a mut Ty: Cismutable<'a, Ty, Is, &'a mut Is>,
178 {
179 match cismute::mutable(from) {
180 Ok(v) => v,
181 Err(_) => unreachable_unchecked(),
182 }
183 }
184
185 /// Analogous to [`cismute::mutable`], but using a live witness to assure that the types are
186 /// the same. This will `panic!()` if the types are not actually the same.
187 #[inline(always)]
188 pub fn mutable<'a>(&self, from: &'a mut Ty) -> &'a mut Is
189 where
190 Ty: 'static,
191 Is: 'static,
192 &'a mut Ty: Cismutable<'a, Ty, Is, &'a mut Is>,
193 {
194 match cismute::mutable(from) {
195 Ok(v) => v,
196 Err(_) => cisunreachable!(),
197 }
198 }
199}
200
201// This Source Code Form is subject to the terms of the Mozilla Public
202// License, v. 2.0. If a copy of the MPL was not distributed with this
203// file, You can obtain one at http://mozilla.org/MPL/2.0/.