Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add examples to clarify the casting rules #686

Merged
merged 3 commits into from
Nov 14, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions src/expressions/operator-expr.md
Original file line number Diff line number Diff line change
Expand Up @@ -398,25 +398,84 @@ reference types and `mut` or `const` in pointer types.

* Casting between two integers of the same size (e.g. i32 -> u32) is a no-op
(Rust uses 2's complement for negative values of fixed integers)

```rust
assert_eq!(42i8 as u8, 42u8);
assert_eq!(-1i8 as u8, 255u8);
assert_eq!(255u8 as i8, -1i8);
assert_eq!(-1i16 as u16, 65535u16);
```

* Casting from a larger integer to a smaller integer (e.g. u32 -> u8) will
truncate

```rust
assert_eq!(42u16 as u8, 42u8);
assert_eq!(1234u16 as u8, 210u8);
assert_eq!(0xabcdu16 as u8, 0xcdu8);

assert_eq!(-42i16 as i8, -42i8);
assert_eq!(1234u16 as i8, -46i8);
assert_eq!(0xabcdi32 as i8, -51i8);
```

* Casting from a smaller integer to a larger integer (e.g. u8 -> u32) will
* zero-extend if the source is unsigned
* sign-extend if the source is signed

```rust
assert_eq!(42i8 as i16, 42i16);
assert_eq!(-17i8 as i16, -17i16);
assert_eq!(0b1000_1010u8 as u16, 0b0000_0000_1000_1010u16, "Zero-extend");
assert_eq!(0b0000_1010i8 as i16, 0b0000_0000_0000_1010i16, "Sign-extend 0");
assert_eq!(0b1000_1010u8 as i8 as i16, 0b1111_1111_1000_1010u16 as i16, "Sign-extend 1");
```

* Casting from a float to an integer will round the float towards zero
* `NaN` will return `0`
* Values larger than the maximum integer value, including `INFINITY`, will saturate to the maximum value of the integer type.
* Values smaller than the minimum integer value, including `NEG_INFINITY`, will saturate to the minimum value of the integer type.

```rust
assert_eq!(42.9f32 as i32, 42);
assert_eq!(-42.9f32 as i32, -42);
assert_eq!(42_000_000f32 as i32, 42_000_000);
assert_eq!(std::f32::NAN as i32, 0);
assert_eq!(1_000_000_000_000_000f32 as i32, 0x7fffffffi32);
assert_eq!(std::f32::NEG_INFINITY as i32, -0x80000000i32);
```

* Casting from an integer to float will produce the closest possible float \*
* if necessary, rounding is according to `roundTiesToEven` mode \*\*\*
* on overflow, infinity (of the same sign as the input) is produced
* note: with the current set of numeric types, overflow can only happen
on `u128 as f32` for values greater or equal to `f32::MAX + (0.5 ULP)`

```rust
assert_eq!(1337i32 as f32, 1337f32);
assert_eq!(123_456_789i32 as f32, 123_456_790f32, "Rounded");
assert_eq!(0xffffffff_ffffffff_ffffffff_ffffffff_u128 as f32, std::f32::INFINITY);
```

* Casting from an f32 to an f64 is perfect and lossless

```rust
assert_eq!(1_234.5f32 as f64, 1_234.5f64);
assert_eq!(std::f32::INFINITY as f64, std::f64::INFINITY);
assert!((std::f32::NAN as f64).is_nan());
```

* Casting from an f64 to an f32 will produce the closest possible f32 \*\*
* if necessary, rounding is according to `roundTiesToEven` mode \*\*\*
* on overflow, infinity (of the same sign as the input) is produced

```rust
assert_eq!(1_234.5f64 as f32, 1_234.5f32);
assert_eq!(1_234_567_891.123f64 as f32, 1_234_567_890f32, "Rounded");
assert_eq!(std::f64::INFINITY as f32, std::f32::INFINITY);
assert!((std::f64::NAN as f32).is_nan());
```

\* if integer-to-float casts with this rounding mode and overflow behavior are
not supported natively by the hardware, these casts will likely be slower than
expected.
Expand All @@ -437,15 +496,34 @@ Casting is limited to the following kinds of enumerations:
* [Unit-only enums]
* [Field-less enums] without [explicit discriminants], or where only unit-variants have explicit discriminants

```rust
enum Enum { A, B, C }
assert_eq!(Enum::A as i32, 0);
assert_eq!(Enum::B as i32, 1);
assert_eq!(Enum::C as i32, 2);
```

#### Primitive to integer cast

* `false` casts to `0`, `true` casts to `1`
* `char` casts to the value of the code point, then uses a numeric cast if needed.

```rust
assert_eq!(false as i32, 0);
assert_eq!(true as i32, 1);
assert_eq!('A' as i32, 65);
assert_eq!('Ö' as i32, 214);
```

#### `u8` to `char` cast

Casts to the `char` with the corresponding code point.

```rust
assert_eq!(65u8 as char, 'A');
assert_eq!(214u8 as char, 'Ö');
```

#### Pointer to address cast

Casting from a raw pointer to an integer produces the machine address of the referenced memory.
Expand Down