some conversions cleanup

pull/10/head
Alexis Beingessner 9 years ago committed by Manish Goregaokar
parent e8f82c31c4
commit 42ed931268

@ -1,9 +1,21 @@
% Casts % Casts
Casts are a superset of coercions: every coercion can be explicitly invoked via Casts are a superset of coercions: every coercion can be explicitly
a cast, but some conversions *require* a cast. These "true casts" are generally invoked via a cast. However some conversions *require* a cast.
regarded as dangerous or problematic actions. True casts revolve around raw While coercions are pervasive and largely harmless, these "true casts"
pointers and the primitive numeric types. True casts aren't checked. are rare and potentially dangerous. As such, casts must be explicitly invoked
using the `as` keyword: `expr as Type`.
True casts generally revolve around raw pointers and the primitive numeric
types. Even though they're dangerous, these casts are *infallible* at runtime.
If a cast triggers some subtle corner case no indication will be given that
this occurred. The cast will simply succeed.
That said, casts aren't `unsafe` because they generally can't violate memory
safety *on their own*. For instance, converting an integer to a raw pointer can
very easily lead to terrible things. However the act of creating the pointer
itself is safe, because actually using a raw pointer is already marked as
`unsafe`.
Here's an exhaustive list of all the true casts. For brevity, we will use `*` Here's an exhaustive list of all the true casts. For brevity, we will use `*`
to denote either a `*const` or `*mut`, and `integer` to denote any integral to denote either a `*const` or `*mut`, and `integer` to denote any integral
@ -22,13 +34,8 @@ primitive:
* `fn as *T` where `T: Sized` * `fn as *T` where `T: Sized`
* `fn as integer` * `fn as integer`
where `&.T` and `*T` are references of either mutability,
and where unsize_kind(`T`) is the kind of the unsize info
in `T` - the vtable for a trait definition (e.g. `fmt::Display` or
`Iterator`, not `Iterator<Item=u8>`) or a length (or `()` if `T: Sized`).
Note that lengths are not adjusted when casting raw slices - Note that lengths are not adjusted when casting raw slices -
`T: *const [u16] as *const [u8]` creates a slice that only includes `*const [u16] as *const [u8]` creates a slice that only includes
half of the original memory. half of the original memory.
Casting is not transitive, that is, even if `e as U1 as U2` is a valid Casting is not transitive, that is, even if `e as U1 as U2` is a valid

@ -9,8 +9,7 @@ Here's all the kinds of coercion:
Coercion is allowed between the following types: Coercion is allowed between the following types:
* Subtyping: `T` to `U` if `T` is a [subtype](lifetimes.html#subtyping-and-variance) * Subtyping: `T` to `U` if `T` is a [subtype][] of `U`
of `U`
* Transitivity: `T_1` to `T_3` where `T_1` coerces to `T_2` and `T_2` coerces to `T_3` * Transitivity: `T_1` to `T_3` where `T_1` coerces to `T_2` and `T_2` coerces to `T_3`
* Pointer Weakening: * Pointer Weakening:
* `&mut T` to `&T` * `&mut T` to `&T`
@ -25,7 +24,6 @@ only implemented automatically, and enables the following transformations:
* `[T, ..n]` => `[T]` * `[T, ..n]` => `[T]`
* `T` => `Trait` where `T: Trait` * `T` => `Trait` where `T: Trait`
* `SubTrait` => `Trait` where `SubTrait: Trait` (TODO: is this now implied by the previous?)
* `Foo<..., T, ...>` => `Foo<..., U, ...>` where: * `Foo<..., T, ...>` => `Foo<..., U, ...>` where:
* `T: Unsize<U>` * `T: Unsize<U>`
* `Foo` is a struct * `Foo` is a struct
@ -70,3 +68,5 @@ fn main() {
<anon>:10 foo(t); <anon>:10 foo(t);
^~~ ^~~
``` ```
[subtype]: subtyping.html

@ -1,9 +1,12 @@
% Type Conversions % Type Conversions
At the end of the day, everything is just a pile of bits somewhere, and type At the end of the day, everything is just a pile of bits somewhere, and type
systems are just there to help us use those bits right. Needing to reinterpret systems are just there to help us use those bits right. There are two common
those piles of bits as different types is a common problem and Rust consequently problems with typing bits: needing to reinterpret those exact bits as a
gives you several ways to do that. different type, and needing to change the bits to have equivalent meaning for
a different type. Because Rust encourages encoding important properties in the
type system, these problems are incredibly pervasive. As such, Rust
consequently gives you several ways to solve them.
First we'll look at the ways that *Safe Rust* gives you to reinterpret values. First we'll look at the ways that *Safe Rust* gives you to reinterpret values.
The most trivial way to do this is to just destructure a value into its The most trivial way to do this is to just destructure a value into its
@ -26,6 +29,6 @@ fn reinterpret(foo: Foo) -> Bar {
} }
``` ```
But this is, at best, annoying to do. For common conversions, Rust provides But this is, at best, annoying. For common conversions, Rust provides
more ergonomic alternatives. more ergonomic alternatives.

@ -1,10 +1,10 @@
% Transmutes % Transmutes
Get out of our way type system! We're going to reinterpret these bits or die Get out of our way type system! We're going to reinterpret these bits or die
trying! Even though this book is all about doing things that are unsafe, I really trying! Even though this book is all about doing things that are unsafe, I
can't emphasize that you should deeply think about finding Another Way than the really can't emphasize that you should deeply think about finding Another Way
operations covered in this section. This is really, truly, the most horribly than the operations covered in this section. This is really, truly, the most
unsafe thing you can do in Rust. The railguards here are dental floss. horribly unsafe thing you can do in Rust. The railguards here are dental floss.
`mem::transmute<T, U>` takes a value of type `T` and reinterprets it to have `mem::transmute<T, U>` takes a value of type `T` and reinterprets it to have
type `U`. The only restriction is that the `T` and `U` are verified to have the type `U`. The only restriction is that the `T` and `U` are verified to have the
@ -17,8 +17,11 @@ same size. The ways to cause Undefined Behaviour with this are mind boggling.
* Making a primitive with an invalid value is UB * Making a primitive with an invalid value is UB
* Transmuting between non-repr(C) types is UB * Transmuting between non-repr(C) types is UB
* Transmuting an & to &mut is UB * Transmuting an & to &mut is UB
* Transmuting an & to &mut is *always* UB
* No you can't do it
* No you're not special
* Transmuting to a reference without an explicitly provided lifetime * Transmuting to a reference without an explicitly provided lifetime
produces an [unbound lifetime](lifetimes.html#unbounded-lifetimes) produces an [unbounded lifetime][]
`mem::transmute_copy<T, U>` somehow manages to be *even more* wildly unsafe than `mem::transmute_copy<T, U>` somehow manages to be *even more* wildly unsafe than
this. It copies `size_of<U>` bytes out of an `&T` and interprets them as a `U`. this. It copies `size_of<U>` bytes out of an `&T` and interprets them as a `U`.
@ -26,4 +29,7 @@ The size check that `mem::transmute` has is gone (as it may be valid to copy
out a prefix), though it is Undefined Behaviour for `U` to be larger than `T`. out a prefix), though it is Undefined Behaviour for `U` to be larger than `T`.
Also of course you can get most of the functionality of these functions using Also of course you can get most of the functionality of these functions using
pointer casts. pointer casts.
[unbounded lifetime]: unbounded-lifetimes.html

Loading…
Cancel
Save