2018-10-29 10:16:55 +00:00
|
|
|
|
use byteorder::{ByteOrder, LittleEndian};
|
|
|
|
|
use core::{f32, i32, i64, u32, u64};
|
2018-10-31 15:01:20 +00:00
|
|
|
|
use nan_preserving_float::{F32, F64};
|
|
|
|
|
use types::ValueType;
|
2018-02-06 11:14:57 +00:00
|
|
|
|
use TrapKind;
|
2018-01-17 15:32:33 +00:00
|
|
|
|
|
2018-11-28 13:01:51 +00:00
|
|
|
|
/// Error for `LittleEndianConvert`
|
2018-02-06 11:14:57 +00:00
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub enum Error {
|
2018-11-28 13:01:51 +00:00
|
|
|
|
/// The buffer is too short for the type being deserialized
|
2018-12-11 11:54:06 +00:00
|
|
|
|
InvalidLittleEndianBuffer,
|
2018-02-06 11:14:57 +00:00
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
|
2018-02-06 20:10:58 +00:00
|
|
|
|
/// Runtime representation of a value.
|
|
|
|
|
///
|
|
|
|
|
/// Wasm code manipulate values of the four basic value types:
|
|
|
|
|
/// integers and floating-point (IEEE 754-2008) data of 32 or 64 bit width each, respectively.
|
|
|
|
|
///
|
|
|
|
|
/// There is no distinction between signed and unsigned integer types. Instead, integers are
|
|
|
|
|
/// interpreted by respective operations as either unsigned or signed in two’s complement representation.
|
2018-01-17 15:32:33 +00:00
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
|
|
|
|
pub enum RuntimeValue {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
/// Value of 32-bit signed or unsigned integer.
|
|
|
|
|
I32(i32),
|
|
|
|
|
/// Value of 64-bit signed or unsigned integer.
|
|
|
|
|
I64(i64),
|
|
|
|
|
/// Value of 32-bit IEEE 754-2008 floating point number.
|
|
|
|
|
F32(F32),
|
|
|
|
|
/// Value of 64-bit IEEE 754-2008 floating point number.
|
|
|
|
|
F64(F64),
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-03-13 22:23:12 +00:00
|
|
|
|
/// Trait for creating value from a [`RuntimeValue`].
|
|
|
|
|
///
|
|
|
|
|
/// Typically each implementation can create a value from the specific type.
|
|
|
|
|
/// For example, values of type `bool` or `u32` are both represented by [`I32`] and `f64` values are represented by
|
|
|
|
|
/// [`F64`].
|
|
|
|
|
///
|
|
|
|
|
/// [`I32`]: enum.RuntimeValue.html#variant.I32
|
|
|
|
|
/// [`F64`]: enum.RuntimeValue.html#variant.F64
|
|
|
|
|
/// [`RuntimeValue`]: enum.RuntimeValue.html
|
2018-10-31 15:01:20 +00:00
|
|
|
|
pub trait FromRuntimeValue
|
|
|
|
|
where
|
2018-12-11 11:54:06 +00:00
|
|
|
|
Self: Sized,
|
2018-10-31 15:01:20 +00:00
|
|
|
|
{
|
2018-12-11 11:54:06 +00:00
|
|
|
|
/// Create a value of type `Self` from a given [`RuntimeValue`].
|
|
|
|
|
///
|
|
|
|
|
/// Returns `None` if the [`RuntimeValue`] is of type different than
|
|
|
|
|
/// expected by the conversion in question.
|
|
|
|
|
///
|
|
|
|
|
/// [`RuntimeValue`]: enum.RuntimeValue.html
|
|
|
|
|
fn from_runtime_value(val: RuntimeValue) -> Option<Self>;
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Convert one type to another by wrapping.
|
|
|
|
|
pub trait WrapInto<T> {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
/// Convert one type to another by wrapping.
|
|
|
|
|
fn wrap_into(self) -> T;
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Convert one type to another by rounding to the nearest integer towards zero.
|
|
|
|
|
pub trait TryTruncateInto<T, E> {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
/// Convert one type to another by rounding to the nearest integer towards zero.
|
|
|
|
|
fn try_truncate_into(self) -> Result<T, E>;
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Convert one type to another by extending with leading zeroes.
|
|
|
|
|
pub trait ExtendInto<T> {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
/// Convert one type to another by extending with leading zeroes.
|
|
|
|
|
fn extend_into(self) -> T;
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Reinterprets the bits of a value of one type as another type.
|
|
|
|
|
pub trait TransmuteInto<T> {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
/// Reinterprets the bits of a value of one type as another type.
|
|
|
|
|
fn transmute_into(self) -> T;
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Convert from and to little endian.
|
2018-10-31 15:01:20 +00:00
|
|
|
|
pub trait LittleEndianConvert
|
|
|
|
|
where
|
2018-12-11 11:54:06 +00:00
|
|
|
|
Self: Sized,
|
2018-10-31 15:01:20 +00:00
|
|
|
|
{
|
2018-12-11 11:54:06 +00:00
|
|
|
|
/// Convert to little endian buffer.
|
|
|
|
|
fn into_little_endian(self, buffer: &mut [u8]);
|
|
|
|
|
/// Convert from little endian buffer.
|
|
|
|
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error>;
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Arithmetic operations.
|
|
|
|
|
pub trait ArithmeticOps<T> {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
/// Add two values.
|
|
|
|
|
fn add(self, other: T) -> T;
|
|
|
|
|
/// Subtract two values.
|
|
|
|
|
fn sub(self, other: T) -> T;
|
|
|
|
|
/// Multiply two values.
|
|
|
|
|
fn mul(self, other: T) -> T;
|
|
|
|
|
/// Divide two values.
|
|
|
|
|
fn div(self, other: T) -> Result<T, TrapKind>;
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Integer value.
|
|
|
|
|
pub trait Integer<T>: ArithmeticOps<T> {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
/// Counts leading zeros in the bitwise representation of the value.
|
|
|
|
|
fn leading_zeros(self) -> T;
|
|
|
|
|
/// Counts trailing zeros in the bitwise representation of the value.
|
|
|
|
|
fn trailing_zeros(self) -> T;
|
|
|
|
|
/// Counts 1-bits in the bitwise representation of the value.
|
|
|
|
|
fn count_ones(self) -> T;
|
|
|
|
|
/// Get left bit rotation result.
|
|
|
|
|
fn rotl(self, other: T) -> T;
|
|
|
|
|
/// Get right bit rotation result.
|
|
|
|
|
fn rotr(self, other: T) -> T;
|
|
|
|
|
/// Get division remainder.
|
|
|
|
|
fn rem(self, other: T) -> Result<T, TrapKind>;
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Float-point value.
|
|
|
|
|
pub trait Float<T>: ArithmeticOps<T> {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
/// Get absolute value.
|
|
|
|
|
fn abs(self) -> T;
|
|
|
|
|
/// Returns the largest integer less than or equal to a number.
|
|
|
|
|
fn floor(self) -> T;
|
|
|
|
|
/// Returns the smallest integer greater than or equal to a number.
|
|
|
|
|
fn ceil(self) -> T;
|
|
|
|
|
/// Returns the integer part of a number.
|
|
|
|
|
fn trunc(self) -> T;
|
|
|
|
|
/// Returns the nearest integer to a number. Round half-way cases away from 0.0.
|
|
|
|
|
fn round(self) -> T;
|
|
|
|
|
/// Returns the nearest integer to a number. Ties are round to even number.
|
|
|
|
|
fn nearest(self) -> T;
|
|
|
|
|
/// Takes the square root of a number.
|
|
|
|
|
fn sqrt(self) -> T;
|
|
|
|
|
/// Returns the minimum of the two numbers.
|
|
|
|
|
fn min(self, other: T) -> T;
|
|
|
|
|
/// Returns the maximum of the two numbers.
|
|
|
|
|
fn max(self, other: T) -> T;
|
|
|
|
|
/// Sets sign of this value to the sign of other value.
|
|
|
|
|
fn copysign(self, other: T) -> T;
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl RuntimeValue {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
/// Creates new default value of given type.
|
|
|
|
|
pub fn default(value_type: ValueType) -> Self {
|
|
|
|
|
match value_type {
|
|
|
|
|
ValueType::I32 => RuntimeValue::I32(0),
|
|
|
|
|
ValueType::I64 => RuntimeValue::I64(0),
|
|
|
|
|
ValueType::F32 => RuntimeValue::F32(0f32.into()),
|
|
|
|
|
ValueType::F64 => RuntimeValue::F64(0f64.into()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Creates new value by interpreting passed u32 as f32.
|
|
|
|
|
pub fn decode_f32(val: u32) -> Self {
|
|
|
|
|
RuntimeValue::F32(F32::from_bits(val))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Creates new value by interpreting passed u64 as f64.
|
|
|
|
|
pub fn decode_f64(val: u64) -> Self {
|
|
|
|
|
RuntimeValue::F64(F64::from_bits(val))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get variable type for this value.
|
|
|
|
|
pub fn value_type(&self) -> ValueType {
|
|
|
|
|
match *self {
|
|
|
|
|
RuntimeValue::I32(_) => ValueType::I32,
|
|
|
|
|
RuntimeValue::I64(_) => ValueType::I64,
|
|
|
|
|
RuntimeValue::F32(_) => ValueType::F32,
|
|
|
|
|
RuntimeValue::F64(_) => ValueType::F64,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns `T` if this particular [`RuntimeValue`] contains
|
|
|
|
|
/// appropriate type.
|
|
|
|
|
///
|
|
|
|
|
/// See [`FromRuntimeValue`] for details.
|
|
|
|
|
///
|
|
|
|
|
/// [`FromRuntimeValue`]: trait.FromRuntimeValue.html
|
|
|
|
|
/// [`RuntimeValue`]: enum.RuntimeValue.html
|
|
|
|
|
pub fn try_into<T: FromRuntimeValue>(self) -> Option<T> {
|
|
|
|
|
FromRuntimeValue::from_runtime_value(self)
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 13:59:30 +00:00
|
|
|
|
impl From<i8> for RuntimeValue {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from(val: i8) -> Self {
|
|
|
|
|
RuntimeValue::I32(val as i32)
|
|
|
|
|
}
|
2018-06-25 13:59:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<i16> for RuntimeValue {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from(val: i16) -> Self {
|
|
|
|
|
RuntimeValue::I32(val as i32)
|
|
|
|
|
}
|
2018-06-25 13:59:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-17 15:32:33 +00:00
|
|
|
|
impl From<i32> for RuntimeValue {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from(val: i32) -> Self {
|
|
|
|
|
RuntimeValue::I32(val)
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<i64> for RuntimeValue {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from(val: i64) -> Self {
|
|
|
|
|
RuntimeValue::I64(val)
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 13:59:30 +00:00
|
|
|
|
impl From<u8> for RuntimeValue {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from(val: u8) -> Self {
|
|
|
|
|
RuntimeValue::I32(val as i32)
|
|
|
|
|
}
|
2018-06-25 13:59:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<u16> for RuntimeValue {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from(val: u16) -> Self {
|
|
|
|
|
RuntimeValue::I32(val as i32)
|
|
|
|
|
}
|
2018-06-25 13:59:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-17 15:32:33 +00:00
|
|
|
|
impl From<u32> for RuntimeValue {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from(val: u32) -> Self {
|
|
|
|
|
RuntimeValue::I32(val.transmute_into())
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<u64> for RuntimeValue {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from(val: u64) -> Self {
|
|
|
|
|
RuntimeValue::I64(val.transmute_into())
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-04-25 07:18:14 +00:00
|
|
|
|
impl From<F32> for RuntimeValue {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from(val: F32) -> Self {
|
|
|
|
|
RuntimeValue::F32(val)
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-04-25 07:18:14 +00:00
|
|
|
|
impl From<F64> for RuntimeValue {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from(val: F64) -> Self {
|
|
|
|
|
RuntimeValue::F64(val)
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-03-13 22:23:12 +00:00
|
|
|
|
macro_rules! impl_from_runtime_value {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
($expected_rt_ty: ident, $into: ty) => {
|
|
|
|
|
impl FromRuntimeValue for $into {
|
|
|
|
|
fn from_runtime_value(val: RuntimeValue) -> Option<Self> {
|
|
|
|
|
match val {
|
|
|
|
|
RuntimeValue::$expected_rt_ty(val) => Some(val.transmute_into()),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-03-13 22:23:12 +00:00
|
|
|
|
/// This conversion assumes that boolean values are represented by
|
|
|
|
|
/// [`I32`] type.
|
|
|
|
|
///
|
|
|
|
|
/// [`I32`]: enum.RuntimeValue.html#variant.I32
|
|
|
|
|
impl FromRuntimeValue for bool {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from_runtime_value(val: RuntimeValue) -> Option<Self> {
|
|
|
|
|
match val {
|
|
|
|
|
RuntimeValue::I32(val) => Some(val != 0),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-25 13:59:30 +00:00
|
|
|
|
/// This conversion assumes that `i8` is represented as an [`I32`].
|
2018-10-29 10:16:55 +00:00
|
|
|
|
///
|
2018-06-25 13:59:30 +00:00
|
|
|
|
/// [`I32`]: enum.RuntimeValue.html#variant.I32
|
|
|
|
|
impl FromRuntimeValue for i8 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from_runtime_value(val: RuntimeValue) -> Option<Self> {
|
|
|
|
|
let min = i8::min_value() as i32;
|
|
|
|
|
let max = i8::max_value() as i32;
|
|
|
|
|
match val {
|
|
|
|
|
RuntimeValue::I32(val) if min <= val && val <= max => Some(val as i8),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-06-25 13:59:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// This conversion assumes that `i16` is represented as an [`I32`].
|
2018-10-29 10:16:55 +00:00
|
|
|
|
///
|
2018-06-25 13:59:30 +00:00
|
|
|
|
/// [`I32`]: enum.RuntimeValue.html#variant.I32
|
|
|
|
|
impl FromRuntimeValue for i16 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from_runtime_value(val: RuntimeValue) -> Option<Self> {
|
|
|
|
|
let min = i16::min_value() as i32;
|
|
|
|
|
let max = i16::max_value() as i32;
|
|
|
|
|
match val {
|
|
|
|
|
RuntimeValue::I32(val) if min <= val && val <= max => Some(val as i16),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-06-25 13:59:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// This conversion assumes that `u8` is represented as an [`I32`].
|
2018-10-29 10:16:55 +00:00
|
|
|
|
///
|
2018-06-25 13:59:30 +00:00
|
|
|
|
/// [`I32`]: enum.RuntimeValue.html#variant.I32
|
|
|
|
|
impl FromRuntimeValue for u8 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from_runtime_value(val: RuntimeValue) -> Option<Self> {
|
|
|
|
|
let min = u8::min_value() as i32;
|
|
|
|
|
let max = u8::max_value() as i32;
|
|
|
|
|
match val {
|
|
|
|
|
RuntimeValue::I32(val) if min <= val && val <= max => Some(val as u8),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-06-25 13:59:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// This conversion assumes that `u16` is represented as an [`I32`].
|
2018-10-29 10:16:55 +00:00
|
|
|
|
///
|
2018-06-25 13:59:30 +00:00
|
|
|
|
/// [`I32`]: enum.RuntimeValue.html#variant.I32
|
|
|
|
|
impl FromRuntimeValue for u16 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from_runtime_value(val: RuntimeValue) -> Option<Self> {
|
|
|
|
|
let min = u16::min_value() as i32;
|
|
|
|
|
let max = u16::max_value() as i32;
|
|
|
|
|
match val {
|
|
|
|
|
RuntimeValue::I32(val) if min <= val && val <= max => Some(val as u16),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-06-25 13:59:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-03-13 22:23:12 +00:00
|
|
|
|
impl_from_runtime_value!(I32, i32);
|
|
|
|
|
impl_from_runtime_value!(I64, i64);
|
2018-04-25 07:18:14 +00:00
|
|
|
|
impl_from_runtime_value!(F32, F32);
|
|
|
|
|
impl_from_runtime_value!(F64, F64);
|
2018-03-13 22:23:12 +00:00
|
|
|
|
impl_from_runtime_value!(I32, u32);
|
|
|
|
|
impl_from_runtime_value!(I64, u64);
|
2018-01-17 15:32:33 +00:00
|
|
|
|
|
|
|
|
|
macro_rules! impl_wrap_into {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
($from:ident, $into:ident) => {
|
|
|
|
|
impl WrapInto<$into> for $from {
|
|
|
|
|
fn wrap_into(self) -> $into {
|
|
|
|
|
self as $into
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
($from:ident, $intermediate:ident, $into:ident) => {
|
|
|
|
|
impl WrapInto<$into> for $from {
|
|
|
|
|
fn wrap_into(self) -> $into {
|
|
|
|
|
$into::from(self as $intermediate)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_wrap_into!(i32, i8);
|
|
|
|
|
impl_wrap_into!(i32, i16);
|
|
|
|
|
impl_wrap_into!(i64, i8);
|
|
|
|
|
impl_wrap_into!(i64, i16);
|
|
|
|
|
impl_wrap_into!(i64, i32);
|
2018-04-25 07:18:14 +00:00
|
|
|
|
impl_wrap_into!(i64, f32, F32);
|
|
|
|
|
impl_wrap_into!(u64, f32, F32);
|
2018-01-17 15:32:33 +00:00
|
|
|
|
// Casting from an f64 to an f32 will produce the closest possible value (rounding strategy unspecified)
|
|
|
|
|
// NOTE: currently this will cause Undefined Behavior if the value is finite but larger or smaller than the
|
|
|
|
|
// largest or smallest finite value representable by f32. This is a bug and will be fixed.
|
|
|
|
|
impl_wrap_into!(f64, f32);
|
|
|
|
|
|
2018-04-25 07:18:14 +00:00
|
|
|
|
impl WrapInto<F32> for F64 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn wrap_into(self) -> F32 {
|
|
|
|
|
(f64::from(self) as f32).into()
|
|
|
|
|
}
|
2018-04-25 07:18:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-17 15:32:33 +00:00
|
|
|
|
macro_rules! impl_try_truncate_into {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
($from: ident, $into: ident) => {
|
|
|
|
|
impl TryTruncateInto<$into, TrapKind> for $from {
|
|
|
|
|
fn try_truncate_into(self) -> Result<$into, TrapKind> {
|
|
|
|
|
// Casting from a float to an integer will round the float towards zero
|
|
|
|
|
// NOTE: currently this will cause Undefined Behavior if the rounded value cannot be represented by the
|
|
|
|
|
// target integer type. This includes Inf and NaN. This is a bug and will be fixed.
|
|
|
|
|
if self.is_nan() || self.is_infinite() {
|
|
|
|
|
return Err(TrapKind::InvalidConversionToInt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// range check
|
|
|
|
|
let result = self as $into;
|
|
|
|
|
if result as $from != self.trunc() {
|
|
|
|
|
return Err(TrapKind::InvalidConversionToInt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(self as $into)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
($from:ident, $intermediate:ident, $into:ident) => {
|
|
|
|
|
impl TryTruncateInto<$into, TrapKind> for $from {
|
|
|
|
|
fn try_truncate_into(self) -> Result<$into, TrapKind> {
|
|
|
|
|
$intermediate::from(self).try_truncate_into()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_try_truncate_into!(f32, i32);
|
|
|
|
|
impl_try_truncate_into!(f32, i64);
|
|
|
|
|
impl_try_truncate_into!(f64, i32);
|
|
|
|
|
impl_try_truncate_into!(f64, i64);
|
|
|
|
|
impl_try_truncate_into!(f32, u32);
|
|
|
|
|
impl_try_truncate_into!(f32, u64);
|
|
|
|
|
impl_try_truncate_into!(f64, u32);
|
|
|
|
|
impl_try_truncate_into!(f64, u64);
|
2018-04-25 07:18:14 +00:00
|
|
|
|
impl_try_truncate_into!(F32, f32, i32);
|
|
|
|
|
impl_try_truncate_into!(F32, f32, i64);
|
|
|
|
|
impl_try_truncate_into!(F64, f64, i32);
|
|
|
|
|
impl_try_truncate_into!(F64, f64, i64);
|
|
|
|
|
impl_try_truncate_into!(F32, f32, u32);
|
|
|
|
|
impl_try_truncate_into!(F32, f32, u64);
|
|
|
|
|
impl_try_truncate_into!(F64, f64, u32);
|
|
|
|
|
impl_try_truncate_into!(F64, f64, u64);
|
2018-01-17 15:32:33 +00:00
|
|
|
|
|
|
|
|
|
macro_rules! impl_extend_into {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
($from:ident, $into:ident) => {
|
|
|
|
|
impl ExtendInto<$into> for $from {
|
|
|
|
|
fn extend_into(self) -> $into {
|
|
|
|
|
self as $into
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
($from:ident, $intermediate:ident, $into:ident) => {
|
|
|
|
|
impl ExtendInto<$into> for $from {
|
|
|
|
|
fn extend_into(self) -> $into {
|
|
|
|
|
$into::from(self as $intermediate)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_extend_into!(i8, i32);
|
|
|
|
|
impl_extend_into!(u8, i32);
|
|
|
|
|
impl_extend_into!(i16, i32);
|
|
|
|
|
impl_extend_into!(u16, i32);
|
|
|
|
|
impl_extend_into!(i8, i64);
|
|
|
|
|
impl_extend_into!(u8, i64);
|
|
|
|
|
impl_extend_into!(i16, i64);
|
|
|
|
|
impl_extend_into!(u16, i64);
|
|
|
|
|
impl_extend_into!(i32, i64);
|
|
|
|
|
impl_extend_into!(u32, i64);
|
|
|
|
|
impl_extend_into!(u32, u64);
|
|
|
|
|
impl_extend_into!(i32, f32);
|
|
|
|
|
impl_extend_into!(i32, f64);
|
|
|
|
|
impl_extend_into!(u32, f32);
|
|
|
|
|
impl_extend_into!(u32, f64);
|
|
|
|
|
impl_extend_into!(i64, f64);
|
|
|
|
|
impl_extend_into!(u64, f64);
|
|
|
|
|
impl_extend_into!(f32, f64);
|
|
|
|
|
|
2018-04-25 07:18:14 +00:00
|
|
|
|
impl_extend_into!(i32, f32, F32);
|
|
|
|
|
impl_extend_into!(i32, f64, F64);
|
|
|
|
|
impl_extend_into!(u32, f32, F32);
|
|
|
|
|
impl_extend_into!(u32, f64, F64);
|
|
|
|
|
impl_extend_into!(i64, f64, F64);
|
|
|
|
|
impl_extend_into!(u64, f64, F64);
|
|
|
|
|
impl_extend_into!(f32, f64, F64);
|
|
|
|
|
|
|
|
|
|
impl ExtendInto<F64> for F32 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn extend_into(self) -> F64 {
|
|
|
|
|
(f32::from(self) as f64).into()
|
|
|
|
|
}
|
2018-04-25 07:18:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-17 15:32:33 +00:00
|
|
|
|
macro_rules! impl_transmute_into_self {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
($type: ident) => {
|
|
|
|
|
impl TransmuteInto<$type> for $type {
|
|
|
|
|
fn transmute_into(self) -> $type {
|
|
|
|
|
self
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_transmute_into_self!(i32);
|
|
|
|
|
impl_transmute_into_self!(i64);
|
|
|
|
|
impl_transmute_into_self!(f32);
|
|
|
|
|
impl_transmute_into_self!(f64);
|
2018-04-25 07:18:14 +00:00
|
|
|
|
impl_transmute_into_self!(F32);
|
|
|
|
|
impl_transmute_into_self!(F64);
|
2018-01-17 15:32:33 +00:00
|
|
|
|
|
|
|
|
|
macro_rules! impl_transmute_into_as {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
($from: ident, $into: ident) => {
|
|
|
|
|
impl TransmuteInto<$into> for $from {
|
|
|
|
|
fn transmute_into(self) -> $into {
|
|
|
|
|
self as $into
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_transmute_into_as!(i8, u8);
|
|
|
|
|
impl_transmute_into_as!(i32, u32);
|
|
|
|
|
impl_transmute_into_as!(i64, u64);
|
|
|
|
|
|
2018-04-25 07:18:14 +00:00
|
|
|
|
macro_rules! impl_transmute_into_npf {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
($npf:ident, $float:ident, $signed:ident, $unsigned:ident) => {
|
|
|
|
|
impl TransmuteInto<$float> for $npf {
|
|
|
|
|
fn transmute_into(self) -> $float {
|
|
|
|
|
self.into()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TransmuteInto<$npf> for $float {
|
|
|
|
|
fn transmute_into(self) -> $npf {
|
|
|
|
|
self.into()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TransmuteInto<$signed> for $npf {
|
|
|
|
|
fn transmute_into(self) -> $signed {
|
|
|
|
|
self.to_bits() as _
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TransmuteInto<$unsigned> for $npf {
|
|
|
|
|
fn transmute_into(self) -> $unsigned {
|
|
|
|
|
self.to_bits()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TransmuteInto<$npf> for $signed {
|
|
|
|
|
fn transmute_into(self) -> $npf {
|
|
|
|
|
$npf::from_bits(self as _)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TransmuteInto<$npf> for $unsigned {
|
|
|
|
|
fn transmute_into(self) -> $npf {
|
|
|
|
|
$npf::from_bits(self)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2018-04-25 07:18:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_transmute_into_npf!(F32, f32, i32, u32);
|
|
|
|
|
impl_transmute_into_npf!(F64, f64, i64, u64);
|
|
|
|
|
|
2018-01-17 15:32:33 +00:00
|
|
|
|
impl TransmuteInto<i32> for f32 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn transmute_into(self) -> i32 {
|
|
|
|
|
self.to_bits() as i32
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TransmuteInto<i64> for f64 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn transmute_into(self) -> i64 {
|
|
|
|
|
self.to_bits() as i64
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TransmuteInto<f32> for i32 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn transmute_into(self) -> f32 {
|
|
|
|
|
f32::from_bits(self as u32)
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TransmuteInto<f64> for i64 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn transmute_into(self) -> f64 {
|
|
|
|
|
f64::from_bits(self as u64)
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-21 12:47:49 +00:00
|
|
|
|
impl TransmuteInto<i32> for u32 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn transmute_into(self) -> i32 {
|
|
|
|
|
self as _
|
|
|
|
|
}
|
2018-06-21 12:47:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TransmuteInto<i64> for u64 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn transmute_into(self) -> i64 {
|
|
|
|
|
self as _
|
|
|
|
|
}
|
2018-06-21 12:47:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-17 15:32:33 +00:00
|
|
|
|
impl LittleEndianConvert for i8 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn into_little_endian(self, buffer: &mut [u8]) {
|
|
|
|
|
buffer[0] = self as u8;
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
|
|
|
|
buffer
|
|
|
|
|
.get(0)
|
|
|
|
|
.map(|v| *v as i8)
|
|
|
|
|
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl LittleEndianConvert for u8 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn into_little_endian(self, buffer: &mut [u8]) {
|
|
|
|
|
buffer[0] = self;
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
|
|
|
|
buffer
|
|
|
|
|
.get(0)
|
|
|
|
|
.cloned()
|
|
|
|
|
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl LittleEndianConvert for i16 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn into_little_endian(self, buffer: &mut [u8]) {
|
|
|
|
|
LittleEndian::write_i16(buffer, self);
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
|
|
|
|
buffer
|
|
|
|
|
.get(0..2)
|
|
|
|
|
.map(LittleEndian::read_i16)
|
|
|
|
|
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl LittleEndianConvert for u16 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn into_little_endian(self, buffer: &mut [u8]) {
|
|
|
|
|
LittleEndian::write_u16(buffer, self);
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
|
|
|
|
buffer
|
|
|
|
|
.get(0..2)
|
|
|
|
|
.map(LittleEndian::read_u16)
|
|
|
|
|
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl LittleEndianConvert for i32 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn into_little_endian(self, buffer: &mut [u8]) {
|
|
|
|
|
LittleEndian::write_i32(buffer, self);
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
|
|
|
|
buffer
|
|
|
|
|
.get(0..4)
|
|
|
|
|
.map(LittleEndian::read_i32)
|
|
|
|
|
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl LittleEndianConvert for u32 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn into_little_endian(self, buffer: &mut [u8]) {
|
|
|
|
|
LittleEndian::write_u32(buffer, self);
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
|
|
|
|
buffer
|
|
|
|
|
.get(0..4)
|
|
|
|
|
.map(LittleEndian::read_u32)
|
|
|
|
|
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl LittleEndianConvert for i64 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn into_little_endian(self, buffer: &mut [u8]) {
|
|
|
|
|
LittleEndian::write_i64(buffer, self);
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
|
|
|
|
buffer
|
|
|
|
|
.get(0..8)
|
|
|
|
|
.map(LittleEndian::read_i64)
|
|
|
|
|
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl LittleEndianConvert for f32 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn into_little_endian(self, buffer: &mut [u8]) {
|
|
|
|
|
LittleEndian::write_f32(buffer, self);
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
|
|
|
|
buffer
|
|
|
|
|
.get(0..4)
|
|
|
|
|
.map(LittleEndian::read_f32)
|
|
|
|
|
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl LittleEndianConvert for f64 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn into_little_endian(self, buffer: &mut [u8]) {
|
|
|
|
|
LittleEndian::write_f64(buffer, self);
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
|
|
|
|
buffer
|
|
|
|
|
.get(0..8)
|
|
|
|
|
.map(LittleEndian::read_f64)
|
|
|
|
|
.ok_or_else(|| Error::InvalidLittleEndianBuffer)
|
|
|
|
|
}
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-04-25 07:18:14 +00:00
|
|
|
|
impl LittleEndianConvert for F32 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn into_little_endian(self, buffer: &mut [u8]) {
|
|
|
|
|
(self.to_bits() as i32).into_little_endian(buffer)
|
|
|
|
|
}
|
2018-04-25 07:18:14 +00:00
|
|
|
|
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
|
|
|
|
i32::from_little_endian(buffer).map(|val| Self::from_bits(val as _))
|
|
|
|
|
}
|
2018-04-25 07:18:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl LittleEndianConvert for F64 {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn into_little_endian(self, buffer: &mut [u8]) {
|
|
|
|
|
(self.to_bits() as i64).into_little_endian(buffer)
|
|
|
|
|
}
|
2018-04-25 07:18:14 +00:00
|
|
|
|
|
2018-12-11 11:54:06 +00:00
|
|
|
|
fn from_little_endian(buffer: &[u8]) -> Result<Self, Error> {
|
|
|
|
|
i64::from_little_endian(buffer).map(|val| Self::from_bits(val as _))
|
|
|
|
|
}
|
2018-04-25 07:18:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-17 15:32:33 +00:00
|
|
|
|
macro_rules! impl_integer_arithmetic_ops {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
($type: ident) => {
|
|
|
|
|
impl ArithmeticOps<$type> for $type {
|
|
|
|
|
fn add(self, other: $type) -> $type {
|
|
|
|
|
self.wrapping_add(other)
|
|
|
|
|
}
|
|
|
|
|
fn sub(self, other: $type) -> $type {
|
|
|
|
|
self.wrapping_sub(other)
|
|
|
|
|
}
|
|
|
|
|
fn mul(self, other: $type) -> $type {
|
|
|
|
|
self.wrapping_mul(other)
|
|
|
|
|
}
|
|
|
|
|
fn div(self, other: $type) -> Result<$type, TrapKind> {
|
|
|
|
|
if other == 0 {
|
|
|
|
|
Err(TrapKind::DivisionByZero)
|
|
|
|
|
} else {
|
|
|
|
|
let (result, overflow) = self.overflowing_div(other);
|
|
|
|
|
if overflow {
|
|
|
|
|
Err(TrapKind::InvalidConversionToInt)
|
|
|
|
|
} else {
|
|
|
|
|
Ok(result)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_integer_arithmetic_ops!(i32);
|
|
|
|
|
impl_integer_arithmetic_ops!(u32);
|
|
|
|
|
impl_integer_arithmetic_ops!(i64);
|
|
|
|
|
impl_integer_arithmetic_ops!(u64);
|
|
|
|
|
|
|
|
|
|
macro_rules! impl_float_arithmetic_ops {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
($type: ident) => {
|
|
|
|
|
impl ArithmeticOps<$type> for $type {
|
|
|
|
|
fn add(self, other: $type) -> $type {
|
|
|
|
|
self + other
|
|
|
|
|
}
|
|
|
|
|
fn sub(self, other: $type) -> $type {
|
|
|
|
|
self - other
|
|
|
|
|
}
|
|
|
|
|
fn mul(self, other: $type) -> $type {
|
|
|
|
|
self * other
|
|
|
|
|
}
|
|
|
|
|
fn div(self, other: $type) -> Result<$type, TrapKind> {
|
|
|
|
|
Ok(self / other)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_float_arithmetic_ops!(f32);
|
|
|
|
|
impl_float_arithmetic_ops!(f64);
|
2018-04-25 07:18:14 +00:00
|
|
|
|
impl_float_arithmetic_ops!(F32);
|
|
|
|
|
impl_float_arithmetic_ops!(F64);
|
2018-01-17 15:32:33 +00:00
|
|
|
|
|
|
|
|
|
macro_rules! impl_integer {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
($type: ident) => {
|
|
|
|
|
impl Integer<$type> for $type {
|
|
|
|
|
fn leading_zeros(self) -> $type {
|
|
|
|
|
self.leading_zeros() as $type
|
|
|
|
|
}
|
|
|
|
|
fn trailing_zeros(self) -> $type {
|
|
|
|
|
self.trailing_zeros() as $type
|
|
|
|
|
}
|
|
|
|
|
fn count_ones(self) -> $type {
|
|
|
|
|
self.count_ones() as $type
|
|
|
|
|
}
|
|
|
|
|
fn rotl(self, other: $type) -> $type {
|
|
|
|
|
self.rotate_left(other as u32)
|
|
|
|
|
}
|
|
|
|
|
fn rotr(self, other: $type) -> $type {
|
|
|
|
|
self.rotate_right(other as u32)
|
|
|
|
|
}
|
|
|
|
|
fn rem(self, other: $type) -> Result<$type, TrapKind> {
|
|
|
|
|
if other == 0 {
|
|
|
|
|
Err(TrapKind::DivisionByZero)
|
|
|
|
|
} else {
|
|
|
|
|
Ok(self.wrapping_rem(other))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_integer!(i32);
|
|
|
|
|
impl_integer!(u32);
|
|
|
|
|
impl_integer!(i64);
|
|
|
|
|
impl_integer!(u64);
|
|
|
|
|
|
2018-10-29 10:16:55 +00:00
|
|
|
|
// Use std float functions in std environment.
|
|
|
|
|
// And libm's implementation in no_std
|
|
|
|
|
#[cfg(feature = "std")]
|
|
|
|
|
macro_rules! call_math {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
($op:ident, $e:expr, $fXX:ident, $FXXExt:ident) => {
|
|
|
|
|
$fXX::$op($e)
|
|
|
|
|
};
|
2018-10-29 10:16:55 +00:00
|
|
|
|
}
|
|
|
|
|
#[cfg(not(feature = "std"))]
|
|
|
|
|
macro_rules! call_math {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
($op:ident, $e:expr, $fXX:ident, $FXXExt:ident) => {
|
|
|
|
|
::libm::$FXXExt::$op($e)
|
|
|
|
|
};
|
2018-10-29 10:16:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We cannot call the math functions directly, because there are multiple available implementaitons in no_std.
|
|
|
|
|
// In std, there are only `Value::$op` and `std::$fXX:$op`.
|
|
|
|
|
// The `std` ones are preferred, because they are not from a trait.
|
|
|
|
|
// For `no_std`, the implementations are `Value::$op` and `libm::FXXExt::$op`,
|
|
|
|
|
// both of which are trait implementations and hence ambiguous.
|
|
|
|
|
// So we have to use a full path, which is what `call_math!` does.
|
|
|
|
|
macro_rules! impl_float {
|
2018-12-11 11:54:06 +00:00
|
|
|
|
($type:ident, $fXX:ident, $FXXExt:ident, $iXX:ident) => {
|
|
|
|
|
impl Float<$type> for $type {
|
|
|
|
|
fn abs(self) -> $type {
|
|
|
|
|
call_math!(abs, $fXX::from(self), $fXX, $FXXExt).into()
|
|
|
|
|
}
|
|
|
|
|
fn floor(self) -> $type {
|
|
|
|
|
call_math!(floor, $fXX::from(self), $fXX, $FXXExt).into()
|
|
|
|
|
}
|
|
|
|
|
fn ceil(self) -> $type {
|
|
|
|
|
call_math!(ceil, $fXX::from(self), $fXX, $FXXExt).into()
|
|
|
|
|
}
|
|
|
|
|
fn trunc(self) -> $type {
|
|
|
|
|
call_math!(trunc, $fXX::from(self), $fXX, $FXXExt).into()
|
|
|
|
|
}
|
|
|
|
|
fn round(self) -> $type {
|
|
|
|
|
call_math!(round, $fXX::from(self), $fXX, $FXXExt).into()
|
|
|
|
|
}
|
|
|
|
|
fn nearest(self) -> $type {
|
|
|
|
|
let round = self.round();
|
|
|
|
|
if call_math!(fract, $fXX::from(self), $fXX, $FXXExt).abs() != 0.5 {
|
|
|
|
|
return round;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
use core::ops::Rem;
|
|
|
|
|
if round.rem(2.0) == 1.0 {
|
|
|
|
|
self.floor()
|
|
|
|
|
} else if round.rem(2.0) == -1.0 {
|
|
|
|
|
self.ceil()
|
|
|
|
|
} else {
|
|
|
|
|
round
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fn sqrt(self) -> $type {
|
|
|
|
|
call_math!(sqrt, $fXX::from(self), $fXX, $FXXExt).into()
|
|
|
|
|
}
|
|
|
|
|
// This instruction corresponds to what is sometimes called "minNaN" in other languages.
|
|
|
|
|
fn min(self, other: $type) -> $type {
|
|
|
|
|
if self.is_nan() {
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
if other.is_nan() {
|
|
|
|
|
return other;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.min(other)
|
|
|
|
|
}
|
|
|
|
|
// This instruction corresponds to what is sometimes called "maxNaN" in other languages.
|
|
|
|
|
fn max(self, other: $type) -> $type {
|
|
|
|
|
if self.is_nan() {
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
if other.is_nan() {
|
|
|
|
|
return other;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.max(other)
|
|
|
|
|
}
|
|
|
|
|
fn copysign(self, other: $type) -> $type {
|
|
|
|
|
use core::mem::size_of;
|
|
|
|
|
|
|
|
|
|
if self.is_nan() {
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let sign_mask: $iXX = 1 << ((size_of::<$iXX>() << 3) - 1);
|
|
|
|
|
let self_int: $iXX = self.transmute_into();
|
|
|
|
|
let other_int: $iXX = other.transmute_into();
|
|
|
|
|
let is_self_sign_set = (self_int & sign_mask) != 0;
|
|
|
|
|
let is_other_sign_set = (other_int & sign_mask) != 0;
|
|
|
|
|
if is_self_sign_set == is_other_sign_set {
|
|
|
|
|
self
|
|
|
|
|
} else if is_other_sign_set {
|
|
|
|
|
(self_int | sign_mask).transmute_into()
|
|
|
|
|
} else {
|
|
|
|
|
(self_int & !sign_mask).transmute_into()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2018-01-17 15:32:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-29 10:16:55 +00:00
|
|
|
|
impl_float!(f32, f32, F32Ext, i32);
|
|
|
|
|
impl_float!(f64, f64, F64Ext, i64);
|
|
|
|
|
impl_float!(F32, f32, F32Ext, i32);
|
|
|
|
|
impl_float!(F64, f64, F64Ext, i64);
|