@@ -5,8 +5,6 @@ are just there to help us use those bits right. Needing to reinterpret those pil
5
5
of bits as different types is a common problem and Rust consequently gives you
6
6
several ways to do that.
7
7
8
- # Safe Rust
9
-
10
8
First we'll look at the ways that * Safe Rust* gives you to reinterpret values. The
11
9
most trivial way to do this is to just destructure a value into its constituent
12
10
parts and then build a new type out of them. e.g.
@@ -31,42 +29,191 @@ fn reinterpret(foo: Foo) -> Bar {
31
29
But this is, at best, annoying to do. For common conversions, rust provides
32
30
more ergonomic alternatives.
33
31
34
- ## Auto-Deref
32
+
33
+
34
+
35
+ # Auto-Deref
36
+
37
+ (Maybe nix this in favour of receiver coercions)
35
38
36
39
Deref is a trait that allows you to overload the unary ` * ` to specify a type
37
40
you dereference to. This is largely only intended to be implemented by pointer
38
41
types like ` & ` , ` Box ` , and ` Rc ` . The dot operator will automatically perform
39
- automatic dereferencing, so that foo.bar() will work uniformly on ` Foo ` , ` &Foo ` , ` &&Foo ` ,
40
- ` &Rc<Box<&mut&Box<Foo>>> ` and so-on. Search bottoms out on the * first* match,
42
+ automatic dereferencing, so that foo.bar() will work uniformly on ` Foo ` , ` &Foo ` , `
43
+ &&Foo ` , ` &Rc<Box<&mut&Box<Foo >>>` and so-on. Search bottoms out on the * first* match,
41
44
so implementing methods on pointers is generally to be avoided, as it will shadow
42
45
"actual" methods.
43
46
44
- ## Coercions
45
47
46
- Types can implicitly be coerced to change in certain contexts. These changes are generally
47
- just * weakening* of types, largely focused around pointers. They mostly exist to make
48
- Rust "just work" in more cases. For instance
49
- ` &mut T ` coerces to ` &T ` , and ` &T ` coerces to ` *const T ` . The most useful coercion you will
50
- actually think about it is probably the general * Deref Coercion* : ` &T ` coerces to ` &U ` when
51
- ` T: Deref<U> ` . This enables us to pass an ` &String ` where an ` &str ` is expected, for instance.
52
48
53
- ## Casts
54
49
55
- Casts are a superset of coercions: every coercion can be explicitly invoked via a cast,
56
- but some changes require a cast. These "true casts" are generally regarded as dangerous or
57
- problematic actions. True casts revolves around raw pointers and the primitive numeric
58
- types. Here's an exhaustive list of all the true casts:
50
+ # Coercions
51
+
52
+ Types can implicitly be coerced to change in certain contexts. These changes are
53
+ generally just * weakening* of types, largely focused around pointers and lifetimes.
54
+ They mostly exist to make Rust "just work" in more cases, and are largely harmless.
55
+
56
+ Here's all the kinds of coercion:
57
+
58
+
59
+ Coercion is allowed between the following types:
60
+
61
+ * ` T ` to ` U ` if ` T ` is a [ subtype] ( lifetimes.html#subtyping-and-variance )
62
+ of ` U ` (the 'identity' case);
63
+
64
+ * ` T_1 ` to ` T_3 ` where ` T_1 ` coerces to ` T_2 ` and ` T_2 ` coerces to ` T_3 `
65
+ (transitivity case);
66
+
67
+ * ` &mut T ` to ` &T ` ;
68
+
69
+ * ` *mut T ` to ` *const T ` ;
70
+
71
+ * ` &T ` to ` *const T ` ;
72
+
73
+ * ` &mut T ` to ` *mut T ` ;
74
+
75
+ * ` T ` to ` U ` if ` T ` implements ` CoerceUnsized<U> ` (see below) and ` T = Foo<...> `
76
+ and ` U = Foo<...> ` ;
77
+
78
+ * From TyCtor(` T ` ) to TyCtor(coerce_inner(` T ` ));
79
+
80
+ where TyCtor(` T ` ) is one of ` &T ` , ` &mut T ` , ` *const T ` , ` *mut T ` , or ` Box<T> ` .
81
+ And where coerce_inner is defined as
82
+
83
+ * coerce_inner(` [T, ..n] ` ) = ` [T] ` ;
84
+
85
+ * coerce_inner(` T ` ) = ` U ` where ` T ` is a concrete type which implements the
86
+ trait ` U ` ;
87
+
88
+ * coerce_inner(` T ` ) = ` U ` where ` T ` is a sub-trait of ` U ` ;
89
+
90
+ * coerce_inner(` Foo<..., T, ...> ` ) = ` Foo<..., coerce_inner(T), ...> ` where
91
+ ` Foo ` is a struct and only the last field has type ` T ` and ` T ` is not part of
92
+ the type of any other fields;
93
+
94
+ * coerce_inner(` (..., T) ` ) = ` (..., coerce_inner(T)) ` .
95
+
96
+ Coercions only occur at a * coercion site* . Exhaustively, the coercion sites
97
+ are:
98
+
99
+ * In ` let ` statements where an explicit type is given: in ` let _: U = e; ` , ` e `
100
+ is coerced to to have type ` U ` ;
101
+
102
+ * In statics and consts, similarly to ` let ` statements;
103
+
104
+ * In argument position for function calls. The value being coerced is the actual
105
+ parameter and it is coerced to the type of the formal parameter. For example,
106
+ where ` foo ` is defined as ` fn foo(x: U) { ... } ` and is called with ` foo(e); ` ,
107
+ ` e ` is coerced to have type ` U ` ;
108
+
109
+ * Where a field of a struct or variant is instantiated. E.g., where `struct Foo
110
+ { x: U }` and the instantiation is ` Foo { x: e }` , ` e` is coerced to to have
111
+ type ` U ` ;
112
+
113
+ * The result of a function, either the final line of a block if it is not semi-
114
+ colon terminated or any expression in a ` return ` statement. For example, for
115
+ ` fn foo() -> U { e } ` , ` e ` is coerced to to have type ` U ` ;
59
116
60
- TODO: gank the RFC for sweet casts
117
+ If the expression in one of these coercion sites is a coercion-propagating
118
+ expression, then the relevant sub-expressions in that expression are also
119
+ coercion sites. Propagation recurses from these new coercion sites. Propagating
120
+ expressions and their relevant sub-expressions are:
61
121
62
- For number -> number casts, there are quite a few cases to consider:
122
+ * array literals, where the array has type ` [U, ..n] ` , each sub-expression in
123
+ the array literal is a coercion site for coercion to type ` U ` ;
124
+
125
+ * array literals with repeating syntax, where the array has type ` [U, ..n] ` , the
126
+ repeated sub-expression is a coercion site for coercion to type ` U ` ;
127
+
128
+ * tuples, where a tuple is a coercion site to type ` (U_0, U_1, ..., U_n) ` , each
129
+ sub-expression is a coercion site for the respective type, e.g., the zero-th
130
+ sub-expression is a coercion site to ` U_0 ` ;
131
+
132
+ * the box expression, if the expression has type ` Box<U> ` , the sub-expression is
133
+ a coercion site to ` U ` ;
134
+
135
+ * parenthesised sub-expressions (` (e) ` ), if the expression has type ` U ` , then
136
+ the sub-expression is a coercion site to ` U ` ;
137
+
138
+ * blocks, if a block has type ` U ` , then the last expression in the block (if it
139
+ is not semicolon-terminated) is a coercion site to ` U ` . This includes blocks
140
+ which are part of control flow statements, such as ` if ` /` else ` , if the block
141
+ has a known type.
142
+
143
+
144
+ Note that we do not perform coercions when matching traits (except for
145
+ receivers, see below). If there is an impl for some type ` U ` and ` T ` coerces to
146
+ ` U ` , that does not constitute an implementation for ` T ` . For example, the
147
+ following will not type check, even though it is OK to coerce ` t ` to ` &T ` and
148
+ there is an impl for ` &T ` :
149
+
150
+ ```
151
+ struct T;
152
+ trait Trait {}
153
+
154
+ fn foo<X: Trait>(t: X) {}
155
+
156
+ impl<'a> Trait for &'a T {}
157
+
158
+
159
+ fn main() {
160
+ let t: &mut T = &mut T;
161
+ foo(t); //~ ERROR failed to find an implementation of trait Trait for &mut T
162
+ }
163
+ ```
164
+
165
+ In a cast expression, ` e as U ` , the compiler will first attempt to coerce ` e ` to
166
+ ` U ` , only if that fails will the conversion rules for casts (see below) be
167
+ applied.
168
+
169
+
170
+
171
+
172
+ # Casts
173
+
174
+ Casts are a superset of coercions: every coercion can be explicitly invoked via a
175
+ cast, but some conversions * require* a cast. These "true casts" are generally regarded
176
+ as dangerous or problematic actions. True casts revolve around raw pointers and
177
+ the primitive numeric types. True casts aren't checked.
178
+
179
+ Here's an exhaustive list of all the true casts:
180
+
181
+ * ` e ` has type ` T ` and ` T ` coerces to ` U ` ; * coercion-cast*
182
+ * ` e ` has type ` *T ` , ` U ` is ` *U_0 ` , and either ` U_0: Sized ` or
183
+ unsize_kind(` T ` ) = unsize_kind(` U_0 ` ); * ptr-ptr-cast*
184
+ * ` e ` has type ` *T ` and ` U ` is a numeric type, while ` T: Sized ` ; * ptr-addr-cast*
185
+ * ` e ` is an integer and ` U ` is ` *U_0 ` , while ` U_0: Sized ` ; * addr-ptr-cast*
186
+ * ` e ` has type ` T ` and ` T ` and ` U ` are any numeric types; * numeric-cast*
187
+ * ` e ` is a C-like enum and ` U ` is an integer type; * enum-cast*
188
+ * ` e ` has type ` bool ` or ` char ` and ` U ` is an integer; * prim-int-cast*
189
+ * ` e ` has type ` u8 ` and ` U ` is ` char ` ; * u8-char-cast*
190
+ * ` e ` has type ` &[T; n] ` and ` U ` is ` *const T ` ; * array-ptr-cast*
191
+ * ` e ` is a function pointer type and ` U ` has type ` *T ` ,
192
+ while ` T: Sized ` ; * fptr-ptr-cast*
193
+ * ` e ` is a function pointer type and ` U ` is an integer; * fptr-addr-cast*
194
+
195
+ where ` &.T ` and ` *T ` are references of either mutability,
196
+ and where unsize_kind(` T ` ) is the kind of the unsize info
197
+ in ` T ` - the vtable for a trait definition (e.g. ` fmt::Display ` or
198
+ ` Iterator ` , not ` Iterator<Item=u8> ` ) or a length (or ` () ` if ` T: Sized ` ).
199
+
200
+ Note that lengths are not adjusted when casting raw slices -
201
+ ` T: *const [u16] as *const [u8] ` creates a slice that only includes
202
+ half of the original memory.
203
+
204
+ Casting is not transitive, that is, even if ` e as U1 as U2 ` is a valid
205
+ expression, ` e as U2 ` is not necessarily so (in fact it will only be valid if
206
+ ` U1 ` coerces to ` U2 ` ).
207
+
208
+ For numeric casts, there are quite a few cases to consider:
63
209
64
210
* casting between two integers of the same size (e.g. i32 -> u32) is a no-op
65
211
* casting from a smaller integer to a bigger integer (e.g. u32 -> u8) will truncate
66
212
* casting from a larger integer to a smaller integer (e.g. u8 -> u32) will
67
- * zero-extend if unsigned
68
- * sign-extend if signed
69
- * casting from a float to an integer will round the float towards zero.
213
+ * zero-extend if the target is unsigned
214
+ * sign-extend if the target is signed
215
+ * casting from a float to an integer will:
216
+ * round the float towards zero if finite
70
217
* ** NOTE: currently this will cause Undefined Behaviour if the rounded
71
218
value cannot be represented by the target integer type** . This is a bug
72
219
and will be fixed.
@@ -86,18 +233,14 @@ well as interpret integers as addresses. However it is impossible to actually
86
233
` unsafe ` .
87
234
88
235
89
- ## Conversion Traits
90
236
91
- For full formal specification of all the kinds of coercions and coercion sites, see:
92
- https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
237
+
238
+ # Conversion Traits
239
+
240
+ TODO
93
241
94
242
95
243
96
- * Coercions
97
- * Casts
98
- * Conversion Traits (Into/As/...)
99
244
100
- # Unsafe Rust
245
+ # Transmuting Types
101
246
102
- * raw ptr casts
103
- * mem::transmute
0 commit comments