From 5e3ae102dbeeb646e8c7d2d423cea263337a76af Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Thu, 12 Feb 2015 22:50:44 +1100 Subject: [PATCH] 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` 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] --- src/libcore/raw.rs | 113 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 5 deletions(-) diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index 3fd244b46e3..81edfe7d6e2 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -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 = slice.repr(); +/// println!("data pointer = {:?}, length = {}", repr.data, repr.len); +/// ``` #[repr(C)] pub struct Slice { pub data: *const T, @@ -30,18 +63,88 @@ pub struct Slice { impl Copy for Slice {} -/// 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`. 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 {