Skip to content

Commit

Permalink
Merge pull request #686 from emilk/add-cast-examples
Browse files Browse the repository at this point in the history
Add examples to clarify the casting rules
  • Loading branch information
ehuss authored Nov 14, 2024
2 parents 5110ba4 + bb6f41b commit 59d3bb2
Showing 1 changed file with 78 additions and 0 deletions.
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

0 comments on commit 59d3bb2

Please sign in to comment.