|
2 | 2 |
|
3 | 3 | r[value]
|
4 | 4 |
|
5 |
| -## Bytes |
6 |
| - |
7 |
| -r[value.byte] |
8 |
| - |
9 |
| -r[value.byte.intro] |
10 |
| -The most basic unit of memory in Rust is a byte. All values in Rust are computed from 0 or more bytes read from an allocation. |
11 |
| - |
12 |
| -> [!NOTE] |
13 |
| -> While bytes in Rust are typically lowered to hardware bytes, they may contain additional values, |
14 |
| -> such as being uninitialized, or storing part of a pointer. |
15 |
| -
|
16 |
| -r[value.byte.init] |
17 |
| -Each byte may be initialized, and contain a value of type `u8`, as well as an optional pointer fragment. |
18 |
| - |
19 |
| -r[value.byte.uninit] |
20 |
| -Each byte may be uninitialized. |
21 |
| - |
22 |
| -> [!NOTE] |
23 |
| -> Uninitialized bytes do not have a value and do not have a pointer fragment. |
24 |
| -
|
25 |
| -## Value Encoding |
26 |
| - |
27 |
| -r[value.encoding] |
28 |
| - |
29 |
| -r[value.encoding.intro] |
30 |
| -Each type in Rust has 0 or more values, which can have operations performed on them |
31 |
| - |
32 |
| -> [!NOTE] |
33 |
| -> `0u8`, `1337i16`, and `Foo{bar: "baz"}` are all values |
34 |
| -
|
35 |
| -r[value.encoding.op] |
36 |
| -Each value of a type can be encoded into a sequence of bytes, and decoded from a sequence of bytes, which has a length equal to the size of the type. |
37 |
| -The operation to encode or decode a value is determined by the representation of the type. |
38 |
| - |
39 |
| -> [!NOTE] |
40 |
| -> Representation is related to, but is not the same property as, the layout of the type. |
41 |
| -
|
42 |
| -r[value.encoding.decode] |
43 |
| -If a value of type `T` is decoded from a sequence of bytes that does not correspond to a defined value, the behavior is undefined. If a value of type `T` is decoded from a sequence of bytes that contain pointer fragments, which are not used to represent the value, the pointer fragments are ignored. |
44 |
| - |
45 |
| -## Pointer Provenance |
46 |
| - |
47 |
| -r[value.provenance] |
48 |
| - |
49 |
| -r[value.provenance.intro] |
50 |
| -Pointer Provenance is a term that refers to additional data carried by pointer values in Rust, beyond its address. When stored in memory, Provenance is encoded in the Pointer Fragment part of each byte of the pointer. |
51 |
| - |
52 |
| -r[value.provenance.allocation] |
53 |
| -Whenever a pointer to a particular allocation is produced by using the reference or raw reference operators, or when a pointer is returned from an allocation function, the resulting pointer has provenance that refers to that allocation. |
54 |
| - |
55 |
| -> [!NOTE] |
56 |
| -> There is additional information encoded by provenance, but the exact scope of this information is not yet decided. |
57 |
| -
|
58 |
| -r[value.provenance.dangling] |
59 |
| -A pointer is dangling if it has no provenance, or if it has provenance to an allocation that has since been deallocated. An access, except for an access of size zero, using a dangling pointer, is undefined behavior. |
60 |
| - |
61 |
| -> [!NOTE] |
62 |
| -> Allocations include local and static variables, as well as temporaries. Local Variables and Temporaries are deallocated when they go out of scope. |
63 |
| -
|
64 |
| -> [!WARN] |
65 |
| -> The above is necessary, but not sufficient, to avoid undefined behavior. The full requirements for pointer access is not yet decided. |
66 |
| -> A reference obtained in safe code is guaranteed to be valid for its usable lifetime, unless interfered with by unsafe code. |
67 |
| -
|
68 |
| -## Primitive Values |
69 |
| - |
70 |
| -r[value.primitive] |
71 |
| - |
72 |
| -r[value.primitive.integer] |
73 |
| -Each value of an integer type is a whole number. For unsigned types, this is a positive integer or `0`. For signed types, this can either be a positive integer, negative integer, or `0`. |
74 |
| - |
75 |
| -r[value.primtive.integer-width] |
76 |
| -The range of values an integer type can represent depends on its signedness and its width, in bits. The width of type `uN` or `iN` is `N`. The width of type `usize` or `isize` is the value of the `target_pointer_width` property. |
77 |
| - |
78 |
| -r[value.primitive.integer-range] |
79 |
| -The range of an unsigned integer type of width `N` is between `0` and `1<<N - 1` inclusive. The range of a signed integer type of width `N` is between `-(1<<(N-1)` and `1<<(N-1) - 1` inclusive. |
80 |
| - |
81 |
| -> [!NOTE] |
82 |
| -> There are exactly `1<<N` unique values of an integer type of width `N`. |
83 |
| -
|
84 |
| -r[value.primitive.unsigned-repr] |
85 |
| -A value `i` of an unsigned integer type `U` is represented by a sequence of initialized bytes, where the `m`th successive byte according to the byte order of the platform is `(i >> (m*8)) as u8`, where `m` is between `0` and the size of `U`. None of the bytes produced by encoding an unsigned integer has a pointer fragment. |
86 |
| - |
87 |
| -> [!NOTE] |
88 |
| -> The two primary byte orders are `little` endian, where the bytes are ordered from lowest memory address to highest, and `big` endian, where the bytes are ordered from highest memory address to lowest. |
89 |
| -> The `cfg` predicate `target_endian` indicates the byte order |
90 |
| -
|
91 |
| -> [!WARN] |
92 |
| -> On `little` endian, the order of bytes used to decode an integer type is the same as the natural order of a `u8` array - that is, the `m` value corresponds with the `m` index into a same-sized `u8` array. On `big` endian, however, the order is the opposite of this order - that is, the `m` value corresponds with the `size_of::<T>() - m` index in that array. |
93 |
| -
|
94 |
| -r[value.primitive.signed-repr] |
95 |
| -A value `i` of a signed integer type with width `N` is represented the same as the corresponding value of the unsigned counterpart type which is congruent modulo `2^N`. |
96 |
| - |
97 |
| -r[value.primitive.char] |
98 |
| -Each value of type `char` is a Unicode Scalar Value, between `U+0000` and `U+10FFFF` (excluding the surrogate range `U+D800` through `U+DFFF`). |
99 |
| - |
100 |
| -r[value.primitive.char-repr] |
101 |
| -The representation of type `char` is the same as the representation of the `u32` corresponding to the Code Point Number encoding by the `char`. |
102 |
| - |
103 |
| -r[value.primitive.bool] |
104 |
| -The two values of type `bool` are `true` and `false`. The representation of `true` is an initialized byte with value `0x01`, and the representation of `false` is an initialized byte with value `0x00`. Neither value is represented with a pointer fragment. |
105 |
| - |
106 |
| -r[value.primitive.float] |
107 |
| -A floating-point value consists of either a rational number, which is within the range and precision dictated by the type, an infinity, or a NaN value. |
108 |
| - |
109 |
| -r[value.primitive.float-repr] |
110 |
| -A floating-point value is represented the same as a value of the unsigned integer type with the same width given by its [IEEE 754-2019] encoding. |
111 |
| - |
112 |
| -r[value.primitive.float-format] |
113 |
| -The [IEEE 754-2019] `binary32` format is used for `f32`, and the `binary64` format is used for `f64`. |
114 |
| - |
115 |
| -[IEEE 754-2019]: https://ieeexplore.ieee.org/document/8766229 |
116 |
| - |
117 |
| -## Pointer Value |
118 |
| - |
119 |
| -r[value.pointer] |
120 |
| - |
121 |
| -r[value.pointer.thin] |
122 |
| -Each thin pointer consists of an address and an optional provenance. The address refers to which byte the pointer points to. The provenance refers to which bytes the pointer is allowed to access, and the allocation those bytes are within. |
123 |
| - |
124 |
| -> [!NOTE] |
125 |
| -> A pointer that does not have a provenance may be called an invalid or dangling pointer. |
126 |
| -
|
127 |
| -r[value.pointer.thin-repr] |
128 |
| -The representation of a value of a thin pointer is a sequence of initialized bytes with `u8` values given by the representation of its address as a value of type `usize`, and pointer fragments corresponding to its provenance, if present. |
129 |
| - |
130 |
| -r[value.pointer.thin-ref] |
131 |
| -A thin reference to `T` consists of a non-null, well aligned address, and provenance for `size_of::<T>()` bytes starting from that address. The representation of a thin reference to `T` is the same as the pointer with the same address and provenance. |
132 |
| - |
133 |
| -> [!NOTE] |
134 |
| -> This is true for both shared and mutable references. There are additional constraints enforced by the aliasing model. |
135 |
| -
|
136 |
| -r[value.pointer.wide] |
137 |
| -A wide pointer or reference consists of a data pointer or reference, and a pointee-specific metadata value. |
138 |
| - |
139 |
| -r[value.pointer.wide-reference] |
140 |
| -The data pointer of a wide reference has a non-null address, well aligned for `align_of_val(self)`, and with provenance for `size_of_val(self)` bytes. |
141 |
| - |
142 |
| -r[value.pointer.wide-representation] |
143 |
| -A wide pointer or reference is represented the same as `struct WidePointer<M>{data: *mut (), metadata: M}` where `M` is the pointee metadata type, and the `data` and `metadata` fields are the corresponding parts of the pointer. |
144 |
| - |
145 |
| -> [!NOTE] |
146 |
| -> The `WidePointer` struct has no guarantees about layout, and has the default representation. |
147 |
| -
|
148 |
| -r[value.pointer.fn] |
149 |
| -A value of a function pointer type consists of an non-null address. A function pointer value is represented the same as an address represented as an unsigned integer type with the same width as the function pointer. |
150 |
| - |
151 |
| -> [!NOTE] |
152 |
| -> Whether or not a function pointer value has provenance, and whether or not this provenance is represented as pointer fragments, is not yet decided. |
153 |
| -
|
154 | 5 | ## Aggregate Values
|
155 | 6 |
|
156 | 7 | r[value.aggregate]
|
|
0 commit comments