Skip to content

Commit 67d6d16

Browse files
committed
Implement cast from lifetime-free to unbound types
1 parent d925dec commit 67d6d16

File tree

2 files changed

+130
-43
lines changed

2 files changed

+130
-43
lines changed

src/internal.rs

Lines changed: 98 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -30,75 +30,131 @@ impl<T: ?Sized> CastToken<T> {
3030
}
3131

3232
/// Supporting trait for autoderef specialization on mutable references to lifetime-free
33-
/// types.
33+
/// target types.
3434
pub trait TryCastMutLifetimeFree<'a, T: ?Sized, U: LifetimeFree + ?Sized> {
3535
#[inline(always)]
3636
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-
}
37+
try_cast_mut_lifetime_free(value)
4838
}
4939
}
5040

5141
impl<'a, T: ?Sized, U: LifetimeFree + ?Sized> TryCastMutLifetimeFree<'a, T, U>
52-
for &&&&&&&(CastToken<&'a mut T>, CastToken<&'a mut U>)
42+
for &&&&&&&&&&(CastToken<&'a mut T>, CastToken<&'a mut U>)
43+
{
44+
}
45+
46+
/// Supporting trait for autoderef specialization on mutable references to lifetime-free
47+
/// source types.
48+
pub trait TryCastMutLifetimeFreeBack<'a, T: LifetimeFree + ?Sized, U: ?Sized> {
49+
#[inline(always)]
50+
fn try_cast(&self, value: &'a mut T) -> Result<&'a mut U, &'a mut T> {
51+
try_cast_mut_lifetime_free(value)
52+
}
53+
}
54+
55+
impl<'a, T: LifetimeFree + ?Sized, U: ?Sized> TryCastMutLifetimeFreeBack<'a, T, U>
56+
for &&&&&&&&&(CastToken<&'a mut T>, CastToken<&'a mut U>)
5357
{
5458
}
5559

60+
// SAFETY: Requires at least one of `T` or `U` to be `LifetimeFree`.
61+
#[inline(always)]
62+
fn try_cast_mut_lifetime_free<T: ?Sized, U: ?Sized>(value: &mut T) -> Result<&mut U, &mut T> {
63+
// SAFETY: See comments on safety in `try_cast_owned_lifetime_free`.
64+
65+
if type_eq_non_static::<T, U>() {
66+
// Pointer casts are not allowed here since the compiler can't prove
67+
// that `&mut T` and `&mut U` have the same kind of associated
68+
// pointer data if they are fat pointers. But we know they are
69+
// identical, so we use a transmute.
70+
Ok(unsafe { transmute_unchecked::<&mut T, &mut U>(value) })
71+
} else {
72+
Err(value)
73+
}
74+
}
75+
5676
/// Supporting trait for autoderef specialization on references to lifetime-free
57-
/// types.
77+
/// target types.
5878
pub trait TryCastRefLifetimeFree<'a, T: ?Sized, U: LifetimeFree + ?Sized> {
5979
#[inline(always)]
6080
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-
}
81+
try_cast_ref_lifetime_free(value)
7282
}
7383
}
7484

7585
impl<'a, T: ?Sized, U: LifetimeFree + ?Sized> TryCastRefLifetimeFree<'a, T, U>
76-
for &&&&&&(CastToken<&'a T>, CastToken<&'a U>)
86+
for &&&&&&&&(CastToken<&'a T>, CastToken<&'a U>)
87+
{
88+
}
89+
90+
/// Supporting trait for autoderef specialization on references to lifetime-free
91+
/// source types.
92+
pub trait TryCastRefLifetimeFreeBack<'a, T: LifetimeFree + ?Sized, U: ?Sized> {
93+
#[inline(always)]
94+
fn try_cast(&self, value: &'a T) -> Result<&'a U, &'a T> {
95+
try_cast_ref_lifetime_free(value)
96+
}
97+
}
98+
99+
impl<'a, T: LifetimeFree + ?Sized, U: ?Sized> TryCastRefLifetimeFreeBack<'a, T, U>
100+
for &&&&&&&(CastToken<&'a T>, CastToken<&'a U>)
77101
{
78102
}
79103

80-
/// Supporting trait for autoderef specialization on lifetime-free types.
104+
// SAFETY: Requires at least one of `T` or `U` to be `LifetimeFree`.
105+
#[inline(always)]
106+
fn try_cast_ref_lifetime_free<T: ?Sized, U: ?Sized>(value: &T) -> Result<&U, &T> {
107+
// SAFETY: See comments on safety in `try_cast_owned_lifetime_free`.
108+
109+
if type_eq_non_static::<T, U>() {
110+
// Pointer casts are not allowed here since the compiler can't prove
111+
// that `&T` and `&U` have the same kind of associated pointer data if
112+
// they are fat pointers. But we know they are identical, so we use
113+
// a transmute.
114+
Ok(unsafe { transmute_unchecked::<&T, &U>(value) })
115+
} else {
116+
Err(value)
117+
}
118+
}
119+
120+
/// Supporting trait for autoderef specialization on lifetime-free target types.
81121
pub trait TryCastOwnedLifetimeFree<T, U: LifetimeFree> {
82122
#[inline(always)]
83123
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-
}
124+
try_cast_owned_lifetime_free(value)
98125
}
99126
}
100127

101-
impl<T, U: LifetimeFree> TryCastOwnedLifetimeFree<T, U> for &&&&&(CastToken<T>, CastToken<U>) {}
128+
impl<T, U: LifetimeFree> TryCastOwnedLifetimeFree<T, U> for &&&&&&(CastToken<T>, CastToken<U>) {}
129+
130+
/// Supporting trait for autoderef specialization on lifetime-free source types.
131+
pub trait TryCastOwnedLifetimeFreeBack<T: LifetimeFree, U> {
132+
#[inline(always)]
133+
fn try_cast(&self, value: T) -> Result<U, T> {
134+
try_cast_owned_lifetime_free(value)
135+
}
136+
}
137+
138+
impl<T: LifetimeFree, U> TryCastOwnedLifetimeFreeBack<T, U> for &&&&&(CastToken<T>, CastToken<U>) {}
139+
140+
// SAFETY: Requires at least one of `T` or `U` to be `LifetimeFree`.
141+
#[inline(always)]
142+
fn try_cast_owned_lifetime_free<T, U>(value: T) -> Result<U, T> {
143+
// SAFETY: If `U` is lifetime-free, and the base types of `T` and `U`
144+
// are equal, then `T` is also lifetime-free. Therefore `T` and `U` are
145+
// strictly identical and it is safe to cast a `T` into a `U`.
146+
//
147+
// We know that `U` is lifetime-free because of the `LifetimeFree` trait
148+
// checked statically. `LifetimeFree` is an unsafe trait implemented for
149+
// individual types, so the burden of verifying that a type is indeed
150+
// lifetime-free is on the implementer.
151+
152+
if type_eq_non_static::<T, U>() {
153+
Ok(unsafe { transmute_unchecked::<T, U>(value) })
154+
} else {
155+
Err(value)
156+
}
157+
}
102158

103159
/// Supporting trait for autoderef specialization on mutable slices.
104160
pub trait TryCastSliceMut<'a, T: 'static, U: 'static> {

src/lib.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,8 @@ macro_rules! cast {
196196
// Note: The number of references added here must be kept in sync with
197197
// the largest number of references used by any trait implementation in
198198
// the internal module.
199-
let result: ::core::result::Result<$T, _> = (&&&&&&&(src_token, dest_token)).try_cast(value);
199+
let result: ::core::result::Result<$T, _> =
200+
(&&&&&&&&&&(src_token, dest_token)).try_cast(value);
200201

201202
result
202203
}};
@@ -353,6 +354,16 @@ mod tests {
353354
}));
354355
}
355356

357+
#[test]
358+
fn cast_lifetime_free_back() {
359+
fn can_cast<T>(value: u8) -> bool {
360+
cast!(value, T).is_ok()
361+
}
362+
363+
assert!(can_cast::<u8>(1));
364+
assert!(!can_cast::<u32>(2));
365+
}
366+
356367
#[test]
357368
fn cast_lifetime_free_unsized_ref() {
358369
fn can_cast<T>(value: &[T]) -> bool {
@@ -365,6 +376,16 @@ mod tests {
365376
assert!(!can_cast(&[&value, &value]));
366377
}
367378

379+
#[test]
380+
fn cast_lifetime_free_unsized_ref_back() {
381+
fn can_cast<T>(value: &[u8]) -> bool {
382+
cast!(value, &[T]).is_ok()
383+
}
384+
385+
assert!(can_cast::<u8>(&[1_u8, 2, 3]));
386+
assert!(!can_cast::<u32>(&[1_u8, 2, 3]));
387+
}
388+
368389
#[test]
369390
fn cast_lifetime_free_unsized_mut() {
370391
fn can_cast<T>(value: &mut [T]) -> bool {
@@ -377,6 +398,16 @@ mod tests {
377398
assert!(!can_cast(&mut [&value, &value]));
378399
}
379400

401+
#[test]
402+
fn cast_lifetime_free_unsized_mut_back() {
403+
fn can_cast<T>(value: &mut [u8]) -> bool {
404+
cast!(value, &mut [T]).is_ok()
405+
}
406+
407+
assert!(can_cast::<u8>(&mut [1_u8, 2, 3]));
408+
assert!(!can_cast::<u32>(&mut [1_u8, 2, 3]));
409+
}
410+
380411
macro_rules! test_lifetime_free_cast {
381412
() => {};
382413

0 commit comments

Comments
 (0)