From 42ed9312686032f7005f75413fcced82b60f9950 Mon Sep 17 00:00:00 2001 From: Alexis Beingessner Date: Sun, 19 Jul 2015 21:43:17 -0700 Subject: [PATCH] some conversions cleanup --- casts.md | 27 +++++++++++++++++---------- coercions.md | 6 +++--- conversions.md | 11 +++++++---- transmutes.md | 18 ++++++++++++------ 4 files changed, 39 insertions(+), 23 deletions(-) diff --git a/casts.md b/casts.md index cbcf81d..37f84ea 100644 --- a/casts.md +++ b/casts.md @@ -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`) 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 diff --git a/coercions.md b/coercions.md index df0fdfa..0eb03d2 100644 --- a/coercions.md +++ b/coercions.md @@ -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` * `Foo` is a struct @@ -70,3 +68,5 @@ fn main() { :10 foo(t); ^~~ ``` + +[subtype]: subtyping.html diff --git a/conversions.md b/conversions.md index 56c0500..2309c45 100644 --- a/conversions.md +++ b/conversions.md @@ -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. diff --git a/transmutes.md b/transmutes.md index 577d35d..f19dda0 100644 --- a/transmutes.md +++ b/transmutes.md @@ -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` 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` somehow manages to be *even more* wildly unsafe than this. It copies `size_of` 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`. Also of course you can get most of the functionality of these functions using -pointer casts. \ No newline at end of file +pointer casts. + + +[unbounded lifetime]: unbounded-lifetimes.html