]> git.lizzy.rs Git - rust.git/commitdiff
Copy in some documentation about which casts are legal
authorMartin Pool <mbp@sourcefrog.net>
Sat, 28 Nov 2015 01:10:50 +0000 (17:10 -0800)
committerMartin Pool <mbp@sourcefrog.net>
Sat, 28 Nov 2015 01:15:05 +0000 (17:15 -0800)
src/doc/book/casting-between-types.md

index 148c55e4b9732c96f94e9f8894c65aa2b9465505..4c520e3d6a80f5b4002efc04dd0a6535e4e4ba67 100644 (file)
@@ -7,7 +7,7 @@ most dangerous features of Rust!
 
 # `as`
 
-The `as` keyword does basic casting:
+The `as` keyword does safe casting:
 
 ```rust
 let x: i32 = 5;
@@ -15,7 +15,63 @@ let x: i32 = 5;
 let y = x as i64;
 ```
 
-It only allows certain kinds of casting, however:
+There are three major categories of safe cast: explicit coercions, casts
+between numeric types, and pointer casts.
+
+Casting is not transitive: even if `e as U1 as U2` is a valid
+expression, `e as U2` is not necessarily so (in fact it will only be valid if
+`U1` coerces to `U2`).
+
+
+## Explicit coercions
+
+A cast `e as U` is valid if `e` has type `T` and `T` *coerces* to `U`.
+
+For example:
+
+```rust
+let a = "hello";
+let b = a as String
+```
+
+Coercions always occur implicitly so this form is only for clarity.
+
+## Numeric casts
+
+A cast `e as U` is also valid in any of the following cases:
+
+ * `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast*
+ * `e` is a C-like enum and `U` is an integer type; *enum-cast*
+ * `e` has type `bool` or `char` and `U` is an integer; *prim-int-cast*
+ * `e` has type `u8` and `U` is `char`; *u8-char-cast*
+For example
+
+```rust
+let one = true as u8;
+let at_sign = 64 as char;
+```
+## Pointer casts
+Perhaps surprisingly, it is safe to cast pointers to and from integers, and
+to cast between pointers to different types subject to some constraints. It
+is only unsafe to dereference the pointer.
+
+* `e` has type `*T`, `U` is a pointer to `*U_0`, and either `U_0: Sized` or
+  unsize_kind(`T`) = unsize_kind(`U_0`); a *ptr-ptr-cast*
+* `e` has type `*T` and `U` is a numeric type, while `T: Sized`; *ptr-addr-cast*
+* `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast*
+* `e` has type `&[T; n]` and `U` is `*const T`; *array-ptr-cast*
+* `e` is a function pointer type and `U` has type `*T`,
+  while `T: Sized`; *fptr-ptr-cast*
+* `e` is a function pointer type and `U` is an integer; *fptr-addr-cast*
+
+
+# `transmute`
+
+`as` only allows safe casting, and will for example reject an attempt to
+cast four bytes into a `u32`:
 
 ```rust,ignore
 let a = [0u8, 0u8, 0u8, 0u8];
@@ -31,13 +87,11 @@ let b = a as u32; // four eights makes 32
         ^~~~~~~~
 ```
 
-It’s a ‘non-scalar cast’ because we have multiple values here: the four
+This is a ‘non-scalar cast’ because we have multiple values here: the four
 elements of the array. These kinds of casts are very dangerous, because they
 make assumptions about the way that multiple underlying structures are
 implemented. For this, we need something more dangerous.
 
-# `transmute`
-
 The `transmute` function is provided by a [compiler intrinsic][intrinsics], and
 what it does is very simple, but very scary. It tells Rust to treat a value of
 one type as though it were another type. It does this regardless of the