Crates.io | primitive_promotion |
lib.rs | primitive_promotion |
version | 0.1.4 |
source | src |
created_at | 2022-01-21 05:42:47.690593 |
updated_at | 2022-02-11 01:10:06.36477 |
description | Primitive promotions for primitive numeric types: u16 for u8, i32 for i16, f64 for f32, etc |
homepage | |
repository | https://github.com/JohnScience/primitive_promotion |
max_upload_size | |
id | 518338 |
size | 9,647 |
According to Rust's reference, primitive numeric types in Rust are such:
The unsigned integer types consist of:
Type | Minimum | Maximum |
---|
u8
| 0 | 28-1
u16
| 0 | 216-1
u32
| 0 | 232-1
u64
| 0 | 264-1
u128
| 0 | 2128-1
The signed two's complement integer types consist of:
Type | Minimum | Maximum |
---|
i8
| -(27) | 27-1
i16
| -(215) | 215-1
i32
| -(231) | 231-1
i64
| -(263) | 263-1
i128
| -(2127) | 2127-1
The IEEE 754-2008 "binary32" and "binary64" floating-point types are f32
and
f64
, respectively.
The usize
type is an unsigned integer type with the same number of bits as the
platform's pointer type. It can represent every memory address in the process.
The isize
type is a signed integer type with the same number of bits as the
platform's pointer type. The theoretical upper bound on object and array size
is the maximum isize
value. This ensures that isize
can be used to calculate
differences between pointers into an object or array and can address every byte
within an object along with one byte past the end.
usize
and isize
are at least 16-bits wide.
Note: Many pieces of Rust code may assume that pointers,
usize
, andisize
are either 32-bit or 64-bit. As a consequence, 16-bit pointer support is limited and may require explicit care and acknowledgment from a library to support.
All primitive numeric types, including machine-dependent types, come with known size that can be obtained via core::mem::size_of<T>()
. The greater the size is, the greater the number of possible values that can be represented by the type. Integer intervals as sets are not closed under many operations, notably addition and multiplication. Since u8
represents the integer interval [0..28-1], the same holds for this type. By analogy, the same is true for u16
, u32
, etc. Similarly, the set of values representable by floating point numbers with algebraic structure avoiding imprecision (i.e. distinct from the algebraic structure on floating point numbers) is not closed under many operations as well.
One way to circumvent the problem is to use type promotion. Type promotion allows to use a type representing a superset of the original type. For every primitive numeric type (except for u128
, i128
, and f64
) there is a canonical type promotion. For u8
the canonical type promotion is u16
, for i16
the canonical type promotion is i32
, and so on.
Type | Size | Canonical type promotion | Size of promotion |
---|
i8
| 1 byte | i16
| 2 bytes
i16
| 2 bytes | i32
| 4 bytes
i32
| 4 bytes | i64
| 8 bytes
i64
| 8 bytes | i128
| 16 bytes
i128
| 16 bytes | undefined | undefined
Type | Size | Canonical type promotion | Size of promotion |
---|
u8
| 1 byte | u16
| 2 bytes
u16
| 2 bytes | u32
| 4 bytes
u32
| 4 bytes | u64
| 8 bytes
u64
| 8 bytes | u128
| 16 bytes
u128
| 16 bytes | undefined | undefined
Type | Size | Canonical type promotion | Size of promotion |
---|
f32
| 4 bytes | f64
| 8 bytes
f64
| 8 bytes | undefined | undefined
Theoretically, one could go one step further and define u256
, yet it would not be primitive and even simple operations on that type (such as addition) would not have the corresponding CPU instructions.
Note Strictly speaking, u128
and i128
are poorly supported on current architectures and it may or may not be reasonable to use implementation of PrimitivePromotionExt
extension trait on u64
and i64
. However, if you want to use these implementations, primitive_promotion
crate is what you need because u64
and i64
implement the PrimitivePromotionExt
trait.
You can notice that PrimitivePromotionExt
is quite long to type. To make it shorter, you are advised to rename the imported trait as PP
. Because its uses are meant to be accompanied with fully qualified syntax, such shorthand is indispensible.
use primitive_promotion::PrimitivePromotionExt as PP;
fn midpoint(a: &u8, b: &u8) -> u8 {
// <u8 as TraitName>:: is an example of fully qualified syntax
let a = *a as <u8 as PP>::PrimitivePromotion;
let b = *b as <u8 as PP>::PrimitivePromotion;
((a+b)/2) as u8
}
fn main() {
let a: u8 = u8::MAX;
let b: u8 = u8::MAX;
assert_eq!(midpoint(&a,&b), u8::MAX);
}