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>) {}