castaway/internal.rs
1//! This module contains helper traits and types used by the public-facing
2//! macros. Most are public so they can be accessed by the expanded macro code,
3//! but are not meant to be used by users directly and do not have a stable API.
4//!
5//! The various `TryCast*` traits in this module are referenced in macro
6//! expansions and expose multiple possible implementations of casting with
7//! different generic bounds. The compiler chooses which trait to use to fulfill
8//! the cast based on the trait bounds using the _autoderef_ trick.
9
10use crate::{
11 lifetime_free::LifetimeFree,
12 utils::{transmute_unchecked, type_eq, type_eq_non_static},
13};
14use core::marker::PhantomData;
15
16/// A token struct used to capture a type without taking ownership of any
17/// values. Used to select a cast implementation in macros.
18pub struct CastToken<T: ?Sized>(PhantomData<T>);
19
20impl<T: ?Sized> CastToken<T> {
21 /// Create a cast token for the given type of value.
22 pub const fn of_val(_value: &T) -> Self {
23 Self::of()
24 }
25
26 /// Create a new cast token of the specified type.
27 pub const fn of() -> Self {
28 Self(PhantomData)
29 }
30}
31
32/// Supporting trait for autoderef specialization on mutable references to lifetime-free
33/// types.
34pub trait TryCastMutLifetimeFree<'a, T: ?Sized, U: LifetimeFree + ?Sized> {
35 #[inline(always)]
36 fn try_cast(&self, value: &'a mut T) -> Result<&'a mut U, &'a mut T> {
37 // SAFETY: See comments on safety in `TryCastLifetimeFree`.
38
39 if type_eq_non_static::<T, U>() {
40 // Pointer casts are not allowed here since the compiler can't prove
41 // that `&mut T` and `&mut U` have the same kind of associated
42 // pointer data if they are fat pointers. But we know they are
43 // identical, so we use a transmute.
44 Ok(unsafe { transmute_unchecked::<&mut T, &mut U>(value) })
45 } else {
46 Err(value)
47 }
48 }
49}
50
51impl<'a, T, U: LifetimeFree> TryCastMutLifetimeFree<'a, T, U>
52 for &&&&&&&(CastToken<&'a mut T>, CastToken<&'a mut U>)
53{
54}
55
56/// Supporting trait for autoderef specialization on references to lifetime-free
57/// types.
58pub trait TryCastRefLifetimeFree<'a, T: ?Sized, U: LifetimeFree + ?Sized> {
59 #[inline(always)]
60 fn try_cast(&self, value: &'a T) -> Result<&'a U, &'a T> {
61 // SAFETY: See comments on safety in `TryCastLifetimeFree`.
62
63 if type_eq_non_static::<T, U>() {
64 // Pointer casts are not allowed here since the compiler can't prove
65 // that `&T` and `&U` have the same kind of associated pointer data if
66 // they are fat pointers. But we know they are identical, so we use
67 // a transmute.
68 Ok(unsafe { transmute_unchecked::<&T, &U>(value) })
69 } else {
70 Err(value)
71 }
72 }
73}
74
75impl<'a, T, U: LifetimeFree> TryCastRefLifetimeFree<'a, T, U>
76 for &&&&&&(CastToken<&'a T>, CastToken<&'a U>)
77{
78}
79
80/// Supporting trait for autoderef specialization on lifetime-free types.
81pub trait TryCastOwnedLifetimeFree<T, U: LifetimeFree> {
82 #[inline(always)]
83 fn try_cast(&self, value: T) -> Result<U, T> {
84 // SAFETY: If `U` is lifetime-free, and the base types of `T` and `U`
85 // are equal, then `T` is also lifetime-free. Therefore `T` and `U` are
86 // strictly identical and it is safe to cast a `T` into a `U`.
87 //
88 // We know that `U` is lifetime-free because of the `LifetimeFree` trait
89 // checked statically. `LifetimeFree` is an unsafe trait implemented for
90 // individual types, so the burden of verifying that a type is indeed
91 // lifetime-free is on the implementer.
92
93 if type_eq_non_static::<T, U>() {
94 Ok(unsafe { transmute_unchecked::<T, U>(value) })
95 } else {
96 Err(value)
97 }
98 }
99}
100
101impl<T, U: LifetimeFree> TryCastOwnedLifetimeFree<T, U> for &&&&&(CastToken<T>, CastToken<U>) {}
102
103/// Supporting trait for autoderef specialization on mutable slices.
104pub trait TryCastSliceMut<'a, T: 'static, U: 'static> {
105 /// Attempt to cast a generic mutable slice to a given type if the types are
106 /// equal.
107 ///
108 /// The reference does not have to be static as long as the item type is
109 /// static.
110 #[inline(always)]
111 fn try_cast(&self, value: &'a mut [T]) -> Result<&'a mut [U], &'a mut [T]> {
112 if type_eq::<T, U>() {
113 Ok(unsafe { &mut *(value as *mut [T] as *mut [U]) })
114 } else {
115 Err(value)
116 }
117 }
118}
119
120impl<'a, T: 'static, U: 'static> TryCastSliceMut<'a, T, U>
121 for &&&&(CastToken<&'a mut [T]>, CastToken<&'a mut [U]>)
122{
123}
124
125/// Supporting trait for autoderef specialization on slices.
126pub trait TryCastSliceRef<'a, T: 'static, U: 'static> {
127 /// Attempt to cast a generic slice to a given type if the types are equal.
128 ///
129 /// The reference does not have to be static as long as the item type is
130 /// static.
131 #[inline(always)]
132 fn try_cast(&self, value: &'a [T]) -> Result<&'a [U], &'a [T]> {
133 if type_eq::<T, U>() {
134 Ok(unsafe { &*(value as *const [T] as *const [U]) })
135 } else {
136 Err(value)
137 }
138 }
139}
140
141impl<'a, T: 'static, U: 'static> TryCastSliceRef<'a, T, U>
142 for &&&(CastToken<&'a [T]>, CastToken<&'a [U]>)
143{
144}
145
146/// Supporting trait for autoderef specialization on mutable references.
147pub trait TryCastMut<'a, T: 'static, U: 'static> {
148 /// Attempt to cast a generic mutable reference to a given type if the types
149 /// are equal.
150 ///
151 /// The reference does not have to be static as long as the reference target
152 /// type is static.
153 #[inline(always)]
154 fn try_cast(&self, value: &'a mut T) -> Result<&'a mut U, &'a mut T> {
155 if type_eq::<T, U>() {
156 Ok(unsafe { &mut *(value as *mut T as *mut U) })
157 } else {
158 Err(value)
159 }
160 }
161}
162
163impl<'a, T: 'static, U: 'static> TryCastMut<'a, T, U>
164 for &&(CastToken<&'a mut T>, CastToken<&'a mut U>)
165{
166}
167
168/// Supporting trait for autoderef specialization on references.
169pub trait TryCastRef<'a, T: 'static, U: 'static> {
170 /// Attempt to cast a generic reference to a given type if the types are
171 /// equal.
172 ///
173 /// The reference does not have to be static as long as the reference target
174 /// type is static.
175 #[inline(always)]
176 fn try_cast(&self, value: &'a T) -> Result<&'a U, &'a T> {
177 if type_eq::<T, U>() {
178 Ok(unsafe { &*(value as *const T as *const U) })
179 } else {
180 Err(value)
181 }
182 }
183}
184
185impl<'a, T: 'static, U: 'static> TryCastRef<'a, T, U> for &(CastToken<&'a T>, CastToken<&'a U>) {}
186
187/// Default trait for autoderef specialization.
188pub trait TryCastOwned<T: 'static, U: 'static> {
189 /// Attempt to cast a value to a given type if the types are equal.
190 #[inline(always)]
191 fn try_cast(&self, value: T) -> Result<U, T> {
192 if type_eq::<T, U>() {
193 Ok(unsafe { transmute_unchecked::<T, U>(value) })
194 } else {
195 Err(value)
196 }
197 }
198}
199
200impl<T: 'static, U: 'static> TryCastOwned<T, U> for (CastToken<T>, CastToken<U>) {}