Dramatically expand the docs of std::raw.

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 #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]
This commit is contained in:
Huon Wilson 2015-02-12 22:50:44 +11:00
parent 0fdca30fcb
commit 5e3ae102db

View File

@ -21,7 +21,40 @@
use marker::Copy;
use mem;
/// The representation of a Rust slice
/// The representation of a slice like `&[T]`.
///
/// This struct is guaranteed to have the layout of types like `&[T]`,
/// `&str`, and `Box<[T]>`, but is not the type of such slices
/// (e.g. the fields are not directly accessible on a `&[T]`) nor does
/// it control that layout (changing the definition will not change
/// the layout of a `&[T]`). It is only designed to be used by unsafe
/// code that needs to manipulate the low-level details.
///
/// However, it is not recommended to use this type for such code,
/// since there are alternatives which may be safer:
///
/// - Creating a slice from a data pointer and length can be done with
/// `std::slice::from_raw_parts` or `std::slice::from_raw_parts_mut`
/// instead of `std::mem::transmute`ing a value of type `Slice`.
/// - Extracting the data pointer and length from a slice can be
/// performed with the `as_ptr` (or `as_mut_ptr`) and `len`
/// methods.
///
/// If one does decide to convert a slice value to a `Slice`, the
/// `Repr` trait in this module provides a method for a safe
/// conversion from `&[T]` (and `&str`) to a `Slice`, more type-safe
/// than a call to `transmute`.
///
/// # Examples
///
/// ```
/// use std::raw::{self, Repr};
///
/// let slice: &[u16] = &[1, 2, 3, 4];
///
/// let repr: raw::Slice<u16> = slice.repr();
/// println!("data pointer = {:?}, length = {}", repr.data, repr.len);
/// ```
#[repr(C)]
pub struct Slice<T> {
pub data: *const T,
@ -30,18 +63,88 @@ pub struct Slice<T> {
impl<T> Copy for Slice<T> {}
/// The representation of a Rust closure
/// The representation of an old closure.
#[repr(C)]
#[derive(Copy)]
#[unstable(feature = "core")]
#[deprecated(reason = "unboxed new closures do not have a universal representation; \
`&Fn` (etc) trait objects should use `TraitObject` instead",
since= "1.0.0")]
pub struct Closure {
pub code: *mut (),
pub env: *mut (),
}
/// The representation of a Rust trait object.
/// The representation of a trait object like `&SomeTrait`.
///
/// This struct does not have a `Repr` implementation
/// because there is no way to refer to all trait objects generically.
/// This struct has the same layout as types like `&SomeTrait` and
/// `Box<AnotherTrait>`. The [Static and Dynamic Dispatch chapter of the
/// Book][moreinfo] contains more details about the precise nature of
/// these internals.
///
/// [moreinfo]: ../../book/static-and-dynamic-dispatch.html#representation
///
/// `TraitObject` is guaranteed to match layouts, but it is not the
/// type of trait objects (e.g. the fields are not directly accessible
/// on a `&SomeTrait`) nor does it control that layout (changing the
/// definition will not change the layout of a `&SometTrait`). It is
/// only designed to be used by unsafe code that needs to manipulate
/// the low-level details.
///
/// There is no `Repr` implementation for `TraitObject` because there
/// is no way to refer to all trait objects generically, so the only
/// way to create values of this type is with functions like
/// `std::mem::transmute`. Similarly, the only way to create a true
/// trait object from a `TraitObject` value is with `transmute`.
///
/// Synthesizing a trait object with mismatched types—one where the
/// vtable does not correspond to the type of the value to which the
/// data pointer points—is highly likely to lead to undefined
/// behaviour.
///
/// # Examples
///
/// ```
/// use std::mem;
/// use std::raw;
///
/// // an example trait
/// trait Foo {
/// fn bar(&self) -> i32;
/// }
/// impl Foo for i32 {
/// fn bar(&self) -> i32 {
/// *self + 1
/// }
/// }
///
/// let value: i32 = 123;
///
/// // let the compiler make a trait object
/// let object: &Foo = &value;
///
/// // look at the raw representation
/// let raw_object: raw::TraitObject = unsafe { mem::transmute(object) };
///
/// // the data pointer is the address of `value`
/// assert_eq!(raw_object.data as *const i32, &value as *const _);
///
///
/// let other_value: i32 = 456;
///
/// // construct a new object, pointing to a different `i32`, being
/// // careful to use the `i32` vtable from `object`
/// let synthesized: &Foo = unsafe {
/// mem::transmute(raw::TraitObject {
/// data: &other_value as *const _ as *mut (),
/// vtable: raw_object.vtable
/// })
/// };
///
/// // it should work just like we constructed a trait object out of
/// // `other_value` directly
/// assert_eq!(synthesized.bar(), 457);
/// ```
#[repr(C)]
#[derive(Copy)]
pub struct TraitObject {