Skip to content

Commit

Permalink
Merge pull request #156 from Havvy/reprs
Browse files Browse the repository at this point in the history
New Section - Type Layout
  • Loading branch information
steveklabnik authored Dec 8, 2017
2 parents 32fc52b + c19106d commit d812ea2
Show file tree
Hide file tree
Showing 7 changed files with 377 additions and 27 deletions.
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
- [Type system](type-system.md)
- [Types](types.md)
- [Dynamically Sized Types](dynamically-sized-types.md)
- [Type layout](type-layout.md)
- [Interior mutability](interior-mutability.md)
- [Subtyping](subtyping.md)
- [Type coercions](type-coercions.md)
Expand Down
2 changes: 1 addition & 1 deletion src/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ pub mod m3 {
}
```

### Inline attributes
### Inline attribute

The inline attribute suggests that the compiler should place a copy of
the function or static in the caller, rather than generating code to
Expand Down
2 changes: 1 addition & 1 deletion src/dynamically-sized-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Most types have a fixed size that is known at compile time and implement the
trait [`Sized`][sized]. A type with a size that is known only at run-time is
called a _dynamically sized type_ (_DST_) or (informally) an unsized type.
called a _dynamically sized type_ (_DST_) or, informally, an unsized type.
[Slices] and [trait objects] are two examples of <abbr title="dynamically sized
types">DSTs</abbr>. Such types can only be used in certain cases:

Expand Down
22 changes: 22 additions & 0 deletions src/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
An ‘abstract syntax tree’, or ‘AST’, is an intermediate representation of
the structure of the program when the compiler is compiling it.

### Alignment

The alignment of a value specifies what addresses values are preferred to
start at. Always a power of two. References to a value must be aligned.
[More][alignment].

### Arity

Arity refers to the number of arguments a function or operator takes.
Expand Down Expand Up @@ -69,6 +75,21 @@ Types that can be referred to by a path directly. Specifically [enums],
Prelude, or The Rust Prelude, is a small collection of items - mostly traits - that are
imported into very module of every crate. The traits in the prelude are pervasive.

### Size

The size of a value has two definitions.

The first is that it is how much memory must be allocated to store that value.

The second is that it is the offset in bytes between successive elements in an
array with that item type.

It is a multiple of the alignment, including zero. The size can change
depending on compiler version (as new optimizations are made) and target
platform (similar to how `usize` varies per-platform).

[More][alignment].

### Slice

A slice is dynamically-sized view into a contiguous sequence, written as `[T]`.
Expand Down Expand Up @@ -104,6 +125,7 @@ It allows a type to make certain promises about its behavior.

Generic functions and generic structs can use traits to constrain, or bound, the types they accept.

[alignment]: type-layout.html#size-and-alignment
[enums]: items/enumerations.html
[structs]: items/structs.html
[unions]: items/unions.html
Expand Down
86 changes: 63 additions & 23 deletions src/items/enumerations.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@
> _EnumItemDiscriminant_ :
> &nbsp;&nbsp; `=` [_Expression_]
An _enumeration_ is a simultaneous definition of a nominal [enumerated type] as
well as a set of *constructors*, that can be used to create or pattern-match
values of the corresponding enumerated type.

[enumerated type]: types.html#enumerated-types
An *enumeration*, also referred to as *enum* is a simultaneous definition of a
nominal [enumerated type] as well as a set of *constructors*, that can be used
to create or pattern-match values of the corresponding enumerated type.

Enumerations are declared with the keyword `enum`.

Expand All @@ -45,11 +43,11 @@ let mut a: Animal = Animal::Dog;
a = Animal::Cat;
```

Enumeration constructors can have either named or unnamed fields:
Enum constructors can have either named or unnamed fields:

```rust
enum Animal {
Dog (String, f64),
Dog(String, f64),
Cat { name: String, weight: f64 },
}

Expand All @@ -59,45 +57,87 @@ a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 };

In this example, `Cat` is a _struct-like enum variant_, whereas `Dog` is simply
called an enum variant. Each enum instance has a _discriminant_ which is an
integer associated to it that is used to determine which variant it holds.
integer associated to it that is used to determine which variant it holds. An
opaque reference to this discriminant can be obtained with the
[`mem::discriminant`] function.

## Custom Discriminant Values for Field-Less Enumerations

If there is no data attached to *any* of the variants of an enumeration,
then the discriminant can be directly chosen and accessed.

If a discriminant isn't specified, they start at zero, and add one for each
variant, in order. Each enum value is just its discriminant which you can
specify explicitly:
These enumerations can be cast to integer types with the `as` operator by a
[numeric cast]. The enumeration can optionaly specify which integer each
discriminant gets by following the variant name with `=` and then an integer
literal. If the first variant in the declaration is unspecified, then it is set
to zero. For every unspecified discriminant, it is set to one higher than the
previous variant in the declaration.

```rust
enum Foo {
Bar, // 0
Baz = 123,
Baz = 123, // 123
Quux, // 124
}

let baz_discriminant = Foo::Baz as u32;
assert_eq!(baz_discriminant, 123);
```

The right hand side of the specification is interpreted as an `isize` value,
but the compiler is allowed to use a smaller type in the actual memory layout.
The [`repr` attribute] can be added in order to change the type of the right
hand side and specify the memory layout.
Under the [default representation], the specified discriminant is interpreted as
an `isize` value although the compiler is allowed to use a smaller type in the
actual memory layout. The size and thus acceptable values can be changed by
using a [primitive representation] or the [`C` representation].

[`repr` attribute]: attributes.html#ffi-attributes
It is an error when two variants share the same discriminant.

You can also cast a field-less enum to get its discriminant:
```rust,ignore
enum SharedDiscriminantError {
SharedA = 1,
SharedB = 1
}
```rust
# enum Foo { Baz = 123 }
let x = Foo::Baz as u32; // x is now 123u32
enum SharedDiscriminantError2 {
Zero, // 0
One, // 1
OneToo = 1 // 1 (collision with previous!)
}
```

This only works as long as none of the variants have data attached. If it were
`Baz(i32)`, this is disallowed.
It is also an error to have an unspecified discriminant where the previous
discriminant is the maximum value for the size of the discriminant.

```rust,ignore
#[repr(u8)]
enum OverflowingDiscriminantError {
Max = 255,
MaxPlusOne // Would be 256, but that overflows the enum.
}
#[repr(u8)]
enum OverflowingDiscriminantError2 {
MaxMinusOne = 254, // 254
Max, // 255
MaxPlusOne // Would be 256, but that overflows the enum.
}
```

## Zero-variant Enums

Enums with zero variants are known as *zero-variant enums*. As they have
no valid values, they cannot be instantiated.

```rust
enum ZeroVariants {}
```

[IDENTIFIER]: identifiers.html
[_Generics_]: items.html#type-parameters
[_WhereClause_]: items.html#type-parameters
[_Expression_]: expressions.html
[_TupleFields_]: items/structs.html
[_StructFields_]: items/structs.html
[enumerated type]: types.html#enumerated-types
[`mem::discriminant`]: std/mem/fn.discriminant.html
[numeric cast]: expressions/operator-expr.html#semantics
[`repr` attribute]: attributes.html#ffi-attributes
Loading

0 comments on commit d812ea2

Please sign in to comment.