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 are a superset of coercions: every coercion can be explicitly invoked via
a cast, but some conversions *require* a cast. These "true casts" are generally
regarded as dangerous or problematic actions. True casts revolve around raw
pointers and the primitive numeric types. True casts aren't checked.
Casts are a superset of coercions: every coercion can be explicitly
invoked via a cast. However some conversions *require* a cast.
While coercions are pervasive and largely harmless, these "true casts"
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 `*`
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 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 -
`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.
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:
* Subtyping: `T` to `U` if `T` is a [subtype](lifetimes.html#subtyping-and-variance)
of `U`
* Subtyping: `T` to `U` if `T` is a [subtype][] of `U`
* Transitivity: `T_1` to `T_3` where `T_1` coerces to `T_2` and `T_2` coerces to `T_3`
* Pointer Weakening:
* `&mut T` to `&T`
@ -25,7 +24,6 @@ only implemented automatically, and enables the following transformations:
* `[T, ..n]` => `[T]`
* `T` => `Trait` where `T: Trait`
* `SubTrait` => `Trait` where `SubTrait: Trait` (TODO: is this now implied by the previous?)
* `Foo<..., T, ...>` => `Foo<..., U, ...>` where:
* `T: Unsize<U>`
* `Foo` is a struct
@ -70,3 +68,5 @@ fn main() {
<anon>:10 foo(t);
^~~
```
[subtype]: subtyping.html

@ -1,9 +1,12 @@
% Type Conversions
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
those piles of bits as different types is a common problem and Rust consequently
gives you several ways to do that.
systems are just there to help us use those bits right. There are two common
problems with typing bits: needing to reinterpret those exact bits as a
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.
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.

@ -1,10 +1,10 @@
% Transmutes
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
can't emphasize that you should deeply think about finding Another Way than the
operations covered in this section. This is really, truly, the most horribly
unsafe thing you can do in Rust. The railguards here are dental floss.
trying! Even though this book is all about doing things that are unsafe, I
really can't emphasize that you should deeply think about finding Another Way
than the operations covered in this section. This is really, truly, the most
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
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
* Transmuting between non-repr(C) types 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
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
this. It copies `size_of<U>` bytes out of an `&T` and interprets them as a `U`.
@ -27,3 +30,6 @@ 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
pointer casts.
[unbounded lifetime]: unbounded-lifetimes.html

Loading…
Cancel
Save