Skip to content

Commit 004288e

Browse files
committed
Extend pointer cast to be able to return thin (including extern) types
This is achievable today using a normal `as` cast when the type is known, but allowing this makes it possible to easily cast extern types in generic contexts, as well as `cast` being generally preferable to `as`.
1 parent 9243168 commit 004288e

File tree

4 files changed

+46
-10
lines changed

4 files changed

+46
-10
lines changed

library/core/src/ptr/const_ptr.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ impl<T: ?Sized> *const T {
4343
#[stable(feature = "ptr_cast", since = "1.38.0")]
4444
#[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")]
4545
#[inline]
46-
pub const fn cast<U>(self) -> *const U {
47-
self as _
46+
pub const fn cast<U: ?Sized + Thin>(self) -> *const U {
47+
// TODO: Just use `self as _` when the compiler understands `Thin`
48+
from_raw_parts(self as *const (), ())
4849
}
4950

5051
/// Use the pointer value in a new pointer of another type.

library/core/src/ptr/mut_ptr.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ impl<T: ?Sized> *mut T {
4141
/// Casts to a pointer of another type.
4242
#[stable(feature = "ptr_cast", since = "1.38.0")]
4343
#[rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0")]
44-
#[inline(always)]
45-
pub const fn cast<U>(self) -> *mut U {
46-
self as _
44+
#[inline]
45+
pub const fn cast<U: ?Sized + Thin>(self) -> *mut U {
46+
// TODO: Just use `self as _` when the compiler understands `Thin`
47+
from_raw_parts_mut(self as *mut (), ())
4748
}
4849

4950
/// Use the pointer value in a new pointer of another type.

library/core/src/ptr/non_null.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::marker::Unsize;
66
use crate::mem::{self, MaybeUninit};
77
use crate::num::NonZeroUsize;
88
use crate::ops::{CoerceUnsized, DispatchFromDyn};
9-
use crate::ptr::Unique;
9+
use crate::ptr::{Thin, Unique};
1010
use crate::slice::{self, SliceIndex};
1111

1212
/// `*mut T` but non-zero and [covariant].
@@ -450,9 +450,9 @@ impl<T: ?Sized> NonNull<T> {
450450
#[must_use = "this returns the result of the operation, \
451451
without modifying the original"]
452452
#[inline]
453-
pub const fn cast<U>(self) -> NonNull<U> {
453+
pub const fn cast<U: ?Sized + Thin>(self) -> NonNull<U> {
454454
// SAFETY: `self` is a `NonNull` pointer which is necessarily non-null
455-
unsafe { NonNull::new_unchecked(self.as_ptr() as *mut U) }
455+
unsafe { NonNull::new_unchecked(self.as_ptr().cast()) }
456456
}
457457
}
458458

library/core/tests/ptr.rs

+36-2
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,40 @@ fn test_is_null() {
106106
assert!(em.is_null());
107107
}
108108

109+
#[test]
110+
fn test_cast() {
111+
// `cast` works like `as` for unsized types
112+
let cs: *const [u8] = &[1, 2, 3];
113+
assert_eq!(cs.cast::<u8>(), cs as *const u8);
114+
115+
let ms: *mut [u8] = &mut [1, 2, 3];
116+
assert_eq!(ms.cast::<u8>(), ms as *mut u8);
117+
118+
let ci: *const dyn ToString = &3;
119+
assert_eq!(ci.cast::<u8>(), ci as *const u8);
120+
121+
let mi: *mut dyn ToString = &mut 3;
122+
assert_eq!(mi.cast::<u8>(), mi as *mut u8);
123+
124+
// `cast` can be used to cast between extern types
125+
extern "C" {
126+
type Extern1;
127+
type Extern2;
128+
}
129+
130+
let p: *const u8 = &42;
131+
let e: *const Extern1 = p.cast();
132+
assert_eq!(e.cast::<Extern2>(), e as *const Extern2);
133+
134+
let p: *mut u8 = &mut 42;
135+
let e: *mut Extern1 = p.cast();
136+
assert_eq!(e.cast::<Extern2>(), e as *mut Extern2);
137+
138+
let p: NonNull<u8> = NonNull::from(&42);
139+
let e: NonNull<Extern1> = p.cast();
140+
assert_eq!(Some(e.cast::<Extern2>()), NonNull::new(e.as_ptr() as *mut Extern2));
141+
}
142+
109143
#[test]
110144
fn test_as_ref() {
111145
unsafe {
@@ -485,8 +519,8 @@ fn ptr_metadata() {
485519
let () = metadata(&[4, 7]);
486520
let () = metadata(&(4, String::new()));
487521
let () = metadata(&Pair(4, String::new()));
488-
let () = metadata(ptr::null::<()>() as *const Extern);
489-
let () = metadata(ptr::null::<()>() as *const <&u32 as std::ops::Deref>::Target);
522+
let () = metadata(ptr::null::<()>().cast::<Extern>());
523+
let () = metadata(ptr::null::<()>().cast::<<&u32 as std::ops::Deref>::Target>());
490524

491525
assert_eq!(metadata("foo"), 3_usize);
492526
assert_eq!(metadata(&[4, 7][..]), 2_usize);

0 commit comments

Comments
 (0)