Skip to content

Commit

Permalink
Dramatically expand the docs of std::raw.
Browse files Browse the repository at this point in the history
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]
  • Loading branch information
huonw committed Feb 14, 2015
1 parent 0fdca30 commit 5e3ae10
Showing 1 changed file with 108 additions and 5 deletions.
113 changes: 108 additions & 5 deletions src/libcore/raw.rs
Expand Up @@ -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,
Expand All @@ -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 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
/// })
/// };
///
/// This struct does not have a `Repr` implementation
/// because there is no way to refer to all trait objects generically.
/// // 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 {
Expand Down

0 comments on commit 5e3ae10

Please sign in to comment.