Skip to content

Commit 8cc3fbd

Browse files
committed
Rollup merge of rust-lang#22218 - huonw:raw-docs, r=steveklabnik,huonw
This overhauls the very meager docs that currently exist to clarify various understandable confusions that I've noticed, e.g. people look in `std::raw` for the "real" types of slices like `&[T]`, or think that `Slice<T>` refers to `[T]` (fixes rust-lang#22214). This patch takes the liberty of offering some "style" guidance around `raw::Slice`, since there's more restricted ways to duplicate all functionality connected to it: `std::slice::from_raw_parts{,_mut}` for construction and `.as_{,mut_}ptr` & `.len` for deconstruction. It also deprecates the `std::raw::Closure` type which is now useless for non-type-erased closures, and replaced by `TraitObject` for `&Fn`, `&mut FnMut` etc, so I guess it should be called a: [breaking-change]
2 parents 63091ef + 7a52932 commit 8cc3fbd

File tree

1 file changed

+111
-8
lines changed

1 file changed

+111
-8
lines changed

src/libcore/raw.rs

Lines changed: 111 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,40 @@
2121
use marker::Copy;
2222
use mem;
2323

24-
/// The representation of a Rust slice
24+
/// The representation of a slice like `&[T]`.
25+
///
26+
/// This struct is guaranteed to have the layout of types like `&[T]`,
27+
/// `&str`, and `Box<[T]>`, but is not the type of such slices
28+
/// (e.g. the fields are not directly accessible on a `&[T]`) nor does
29+
/// it control that layout (changing the definition will not change
30+
/// the layout of a `&[T]`). It is only designed to be used by unsafe
31+
/// code that needs to manipulate the low-level details.
32+
///
33+
/// However, it is not recommended to use this type for such code,
34+
/// since there are alternatives which may be safer:
35+
///
36+
/// - Creating a slice from a data pointer and length can be done with
37+
/// `std::slice::from_raw_parts` or `std::slice::from_raw_parts_mut`
38+
/// instead of `std::mem::transmute`ing a value of type `Slice`.
39+
/// - Extracting the data pointer and length from a slice can be
40+
/// performed with the `as_ptr` (or `as_mut_ptr`) and `len`
41+
/// methods.
42+
///
43+
/// If one does decide to convert a slice value to a `Slice`, the
44+
/// `Repr` trait in this module provides a method for a safe
45+
/// conversion from `&[T]` (and `&str`) to a `Slice`, more type-safe
46+
/// than a call to `transmute`.
47+
///
48+
/// # Examples
49+
///
50+
/// ```
51+
/// use std::raw::{self, Repr};
52+
///
53+
/// let slice: &[u16] = &[1, 2, 3, 4];
54+
///
55+
/// let repr: raw::Slice<u16> = slice.repr();
56+
/// println!("data pointer = {:?}, length = {}", repr.data, repr.len);
57+
/// ```
2558
#[repr(C)]
2659
pub struct Slice<T> {
2760
pub data: *const T,
@@ -30,18 +63,88 @@ pub struct Slice<T> {
3063

3164
impl<T> Copy for Slice<T> {}
3265

33-
/// The representation of a Rust closure
66+
/// The representation of an old closure.
3467
#[repr(C)]
3568
#[derive(Copy)]
69+
#[unstable(feature = "core")]
70+
#[deprecated(reason = "unboxed new closures do not have a universal representation; \
71+
`&Fn` (etc) trait objects should use `TraitObject` instead",
72+
since= "1.0.0")]
3673
pub struct Closure {
3774
pub code: *mut (),
3875
pub env: *mut (),
3976
}
4077

41-
/// The representation of a Rust trait object.
78+
/// The representation of a trait object like `&SomeTrait`.
79+
///
80+
/// This struct has the same layout as types like `&SomeTrait` and
81+
/// `Box<AnotherTrait>`. The [Static and Dynamic Dispatch chapter of the
82+
/// Book][moreinfo] contains more details about the precise nature of
83+
/// these internals.
84+
///
85+
/// [moreinfo]: ../../book/static-and-dynamic-dispatch.html#representation
86+
///
87+
/// `TraitObject` is guaranteed to match layouts, but it is not the
88+
/// type of trait objects (e.g. the fields are not directly accessible
89+
/// on a `&SomeTrait`) nor does it control that layout (changing the
90+
/// definition will not change the layout of a `&SometTrait`). It is
91+
/// only designed to be used by unsafe code that needs to manipulate
92+
/// the low-level details.
93+
///
94+
/// There is no `Repr` implementation for `TraitObject` because there
95+
/// is no way to refer to all trait objects generically, so the only
96+
/// way to create values of this type is with functions like
97+
/// `std::mem::transmute`. Similarly, the only way to create a true
98+
/// trait object from a `TraitObject` value is with `transmute`.
99+
///
100+
/// Synthesizing a trait object with mismatched types—one where the
101+
/// vtable does not correspond to the type of the value to which the
102+
/// data pointer points—is highly likely to lead to undefined
103+
/// behaviour.
104+
///
105+
/// # Examples
106+
///
107+
/// ```
108+
/// use std::mem;
109+
/// use std::raw;
110+
///
111+
/// // an example trait
112+
/// trait Foo {
113+
/// fn bar(&self) -> i32;
114+
/// }
115+
/// impl Foo for i32 {
116+
/// fn bar(&self) -> i32 {
117+
/// *self + 1
118+
/// }
119+
/// }
120+
///
121+
/// let value: i32 = 123;
122+
///
123+
/// // let the compiler make a trait object
124+
/// let object: &Foo = &value;
125+
///
126+
/// // look at the raw representation
127+
/// let raw_object: raw::TraitObject = unsafe { mem::transmute(object) };
128+
///
129+
/// // the data pointer is the address of `value`
130+
/// assert_eq!(raw_object.data as *const i32, &value as *const _);
131+
///
132+
///
133+
/// let other_value: i32 = 456;
134+
///
135+
/// // construct a new object, pointing to a different `i32`, being
136+
/// // careful to use the `i32` vtable from `object`
137+
/// let synthesized: &Foo = unsafe {
138+
/// mem::transmute(raw::TraitObject {
139+
/// data: &other_value as *const _ as *mut (),
140+
/// vtable: raw_object.vtable
141+
/// })
142+
/// };
42143
///
43-
/// This struct does not have a `Repr` implementation
44-
/// because there is no way to refer to all trait objects generically.
144+
/// // it should work just like we constructed a trait object out of
145+
/// // `other_value` directly
146+
/// assert_eq!(synthesized.bar(), 457);
147+
/// ```
45148
#[repr(C)]
46149
#[derive(Copy)]
47150
pub struct TraitObject {
@@ -51,7 +154,7 @@ pub struct TraitObject {
51154

52155
/// This trait is meant to map equivalences between raw structs and their
53156
/// corresponding rust values.
54-
pub trait Repr<T> {
157+
pub unsafe trait Repr<T> {
55158
/// This function "unwraps" a rust value (without consuming it) into its raw
56159
/// struct representation. This can be used to read/write different values
57160
/// for the struct. This is a safe method because by default it does not
@@ -60,5 +163,5 @@ pub trait Repr<T> {
60163
fn repr(&self) -> T { unsafe { mem::transmute_copy(&self) } }
61164
}
62165

63-
impl<T> Repr<Slice<T>> for [T] {}
64-
impl Repr<Slice<u8>> for str {}
166+
unsafe impl<T> Repr<Slice<T>> for [T] {}
167+
unsafe impl Repr<Slice<u8>> for str {}

0 commit comments

Comments
 (0)