add Wrapping

This commit is contained in:
Trevor Spiteri 2019-02-27 22:23:50 +01:00
parent 955dfaa618
commit ef5ff4bc99
4 changed files with 605 additions and 16 deletions

View File

@ -547,7 +547,10 @@ macro_rules! fixed_arith {
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
fn sum<I: Iterator<Item = $Fixed<Frac>>>(iter: I) -> $Fixed<Frac> {
fn sum<I>(iter: I) -> $Fixed<Frac>
where
I: Iterator<Item = $Fixed<Frac>>,
{
iter.fold(Self::from_bits(0), Add::add)
}
}
@ -556,7 +559,10 @@ macro_rules! fixed_arith {
where
Frac: 'a + Unsigned + IsLessOrEqual<$Len, Output = True>,
{
fn sum<I: Iterator<Item = &'a $Fixed<Frac>>>(iter: I) -> $Fixed<Frac> {
fn sum<I>(iter: I) -> $Fixed<Frac>
where
I: Iterator<Item = &'a $Fixed<Frac>>,
{
iter.fold(Self::from_bits(0), Add::add)
}
}
@ -565,7 +571,10 @@ macro_rules! fixed_arith {
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
fn product<I: Iterator<Item = $Fixed<Frac>>>(mut iter: I) -> $Fixed<Frac> {
fn product<I>(mut iter: I) -> $Fixed<Frac>
where
I: Iterator<Item = $Fixed<Frac>>,
{
match iter.next() {
None => Self::one().expect("overflow"),
Some(first) => iter.fold(first, Mul::mul),
@ -577,7 +586,10 @@ macro_rules! fixed_arith {
where
Frac: 'a + Unsigned + IsLessOrEqual<$Len, Output = True>,
{
fn product<I: Iterator<Item = &'a $Fixed<Frac>>>(mut iter: I) -> $Fixed<Frac> {
fn product<I>(mut iter: I) -> $Fixed<Frac>
where
I: Iterator<Item = &'a $Fixed<Frac>>,
{
match iter.next() {
None => Self::one().expect("overflow"),
Some(first) => iter.fold(*first, Mul::mul),

View File

@ -211,6 +211,7 @@ mod sealed_int;
mod serdeize;
pub mod types;
mod wide_div;
mod wrapping;
use arith::MulDivDir;
use core::cmp::Ordering;
@ -220,6 +221,7 @@ use frac::{IsLessOrEqual, True, Unsigned, U128, U16, U32, U64, U8};
#[cfg(feature = "f16")]
use half::f16;
use sealed::{Fixed, Float, Int, SealedFixed, SealedFloat, SealedInt, Widest};
pub use wrapping::Wrapping;
#[macro_use]
mod macros_from_to;

View File

@ -14,6 +14,7 @@
// <https://opensource.org/licenses/MIT>.
use core::fmt::{Debug, Display};
use core::hash::Hash;
use frac::{IsLessOrEqual, True, Unsigned, U128, U16, U32, U64, U8};
use sealed::{Fixed, Float, SealedInt};
use {
@ -28,7 +29,7 @@ pub enum Widest {
Negative(i128),
}
pub trait SealedFixed: Copy + Debug + Display {
pub trait SealedFixed: Copy + Debug + Default + Display + Eq + Hash + Ord {
type FracNBits: Unsigned;
type Bits: SealedInt;
@ -83,10 +84,16 @@ pub trait SealedFixed: Copy + Debug + Display {
<Self::Bits as SealedInt>::Unsigned,
<Self::Bits as SealedInt>::Unsigned,
);
fn wrapping_ceil(self) -> Self;
fn wrapping_floor(self) -> Self;
fn wrapping_round(self) -> Self;
fn wrapping_neg(self) -> Self;
fn wrapping_abs(self) -> Self;
}
macro_rules! sealed_fixed {
($Fixed:ident($Bits:ty, $Len:ty)) => {
($Fixed:ident($Bits:ty, $Len:ty, $Signedness:tt)) => {
impl<Frac> SealedFixed for $Fixed<Frac>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
@ -146,17 +153,46 @@ macro_rules! sealed_fixed {
};
(neg, int_abs, frac_abs)
}
#[inline]
fn wrapping_ceil(self) -> Self {
self.wrapping_ceil()
}
#[inline]
fn wrapping_floor(self) -> Self {
self.wrapping_floor()
}
#[inline]
fn wrapping_round(self) -> Self {
self.wrapping_round()
}
#[inline]
fn wrapping_neg(self) -> Self {
self.wrapping_neg()
}
#[inline]
fn wrapping_abs(self) -> Self {
if_signed_unsigned! {
$Signedness,
self.wrapping_abs(),
self,
}
}
}
};
}
sealed_fixed! { FixedI8(i8, U8) }
sealed_fixed! { FixedI16(i16, U16) }
sealed_fixed! { FixedI32(i32, U32) }
sealed_fixed! { FixedI64(i64, U64) }
sealed_fixed! { FixedI128(i128, U128) }
sealed_fixed! { FixedU8(u8, U8) }
sealed_fixed! { FixedU16(u16, U16) }
sealed_fixed! { FixedU32(u32, U32) }
sealed_fixed! { FixedU64(u64, U64) }
sealed_fixed! { FixedU128(u128, U128) }
sealed_fixed! { FixedI8(i8, U8, Signed) }
sealed_fixed! { FixedI16(i16, U16, Signed) }
sealed_fixed! { FixedI32(i32, U32, Signed) }
sealed_fixed! { FixedI64(i64, U64, Signed) }
sealed_fixed! { FixedI128(i128, U128, Signed) }
sealed_fixed! { FixedU8(u8, U8, Unsigned) }
sealed_fixed! { FixedU16(u16, U16, Unsigned) }
sealed_fixed! { FixedU32(u32, U32, Unsigned) }
sealed_fixed! { FixedU64(u64, U64, Unsigned) }
sealed_fixed! { FixedU128(u128, U128, Unsigned) }

539
src/wrapping.rs Normal file
View File

@ -0,0 +1,539 @@
// Copyright © 20182019 Trevor Spiteri
// This library is free software: you can redistribute it and/or
// modify it under the terms of either
//
// * the Apache License, Version 2.0 or
// * the MIT License
//
// at your option.
//
// You should have recieved copies of the Apache License and the MIT
// License along with the library. If not, see
// <https://www.apache.org/licenses/LICENSE-2.0> and
// <https://opensource.org/licenses/MIT>.
use core::cmp::Ordering;
use core::default::Default;
use core::fmt::{Debug, Display, Formatter, Result as FmtResult};
use core::hash::{Hash, Hasher};
use core::iter::{Product, Sum};
use core::num::Wrapping as CoreWrapping;
use core::ops::{
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
};
use frac::{IsLessOrEqual, True, Unsigned, U128, U16, U32, U64, U8};
use sealed::{Fixed, SealedFixed};
use {
FixedI128, FixedI16, FixedI32, FixedI64, FixedI8, FixedU128, FixedU16, FixedU32, FixedU64,
FixedU8,
};
/// Provides intentionally wrapped arithmetic on fixed-point numbers.
///
/// The underlying value can be retrieved through the `.0` index.
///
/// # Examples
///
/// ```rust
/// use fixed::Wrapping;
/// type Fix = fixed::types::I16F16;
/// let max = Wrapping(Fix::max_value());
/// let delta = Wrapping(Fix::from_bits(1));
/// assert_eq!(Fix::min_value(), (max + delta).0);
/// ```
#[repr(transparent)]
pub struct Wrapping<F>(pub F)
where
F: Fixed;
impl<F: Fixed> Wrapping<F> {
/// Wrapping ceil. Rounds to the next integer towards +∞, wrapping
/// on overflow.
///
/// # Examples
///
/// ```rust
/// use fixed::Wrapping;
/// type Fix = fixed::types::I16F16;
/// let two_half = Wrapping(Fix::from_int(5) / 2);
/// assert_eq!(two_half.ceil(), Wrapping(Fix::from_int(3)));
/// assert_eq!(Wrapping(Fix::max_value()).ceil(), Wrapping(Fix::min_value()));
/// ```
pub fn ceil(self) -> Wrapping<F> {
Wrapping((self.0).wrapping_ceil())
}
/// Wrapping floor. Rounds to the next integer towards −∞,
/// wrapping on overflow.
///
/// Overflow can only occur for signed numbers with zero integer
/// bits.
///
/// # Examples
///
/// ```rust
/// use fixed::Wrapping;
/// type Fix = fixed::types::I16F16;
/// let two_half = Wrapping(Fix::from_int(5) / 2);
/// assert_eq!(two_half.floor(), Wrapping(Fix::from_int(2)));
/// type AllFrac = fixed::types::I0F32;
/// assert_eq!(Wrapping(AllFrac::min_value()).floor(), Wrapping(AllFrac::from_int(0)));
/// ```
pub fn floor(self) -> Wrapping<F> {
Wrapping((self.0).wrapping_floor())
}
/// Wrapping round. Rounds to the next integer to the nearest,
/// with ties rounded away from zero, and wrapping on overflow.
///
/// # Examples
///
/// ```rust
/// use fixed::Wrapping;
/// type Fix = fixed::types::I16F16;
/// let two_half = Wrapping(Fix::from_int(5) / 2);
/// assert_eq!(two_half.round(), Wrapping(Fix::from_int(3)));
/// assert_eq!((-two_half).round(), Wrapping(Fix::from_int(-3)));
/// assert_eq!(Wrapping(Fix::max_value()).round(), Wrapping(Fix::min_value()));
/// ```
pub fn round(self) -> Wrapping<F> {
Wrapping((self.0).wrapping_round())
}
/// Wrapping absolute value. Returns the absolute value, wrapping
/// on overflow.
///
/// Overflow can only occur for signed numbers when trying to find
/// the absolute value of the minimum value.
///
/// # Examples
///
/// ```rust
/// use fixed::Wrapping;
/// type Fix = fixed::types::I16F16;
/// assert_eq!(Wrapping(Fix::from_int(-5)).abs(), Wrapping(Fix::from_int(5)));
/// assert_eq!(Wrapping(Fix::min_value()).abs(), Wrapping(Fix::min_value()));
/// ```
pub fn abs(self) -> Wrapping<F> {
Wrapping((self.0).wrapping_abs())
}
}
impl<F> Clone for Wrapping<F>
where
F: Fixed,
{
#[inline]
fn clone(&self) -> Wrapping<F> {
Wrapping(self.0)
}
}
impl<F> Copy for Wrapping<F> where F: Fixed {}
impl<F> Default for Wrapping<F>
where
F: Fixed,
{
#[inline]
fn default() -> Wrapping<F> {
Wrapping(F::default())
}
}
impl<F> Hash for Wrapping<F>
where
F: Fixed,
{
#[inline]
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
(self.0).hash(state);
}
}
impl<F> Debug for Wrapping<F>
where
F: Fixed,
{
#[inline]
fn fmt(&self, f: &mut Formatter) -> FmtResult {
<F as Debug>::fmt(&self.0, f)
}
}
impl<F> Display for Wrapping<F>
where
F: Fixed,
{
#[inline]
fn fmt(&self, f: &mut Formatter) -> FmtResult {
<F as Display>::fmt(&self.0, f)
}
}
impl<F> From<F> for Wrapping<F>
where
F: Fixed,
{
#[inline]
fn from(src: F) -> Wrapping<F> {
Wrapping(src)
}
}
impl<F> Eq for Wrapping<F> where F: Fixed {}
impl<F> PartialEq<Wrapping<F>> for Wrapping<F>
where
F: Fixed,
{
#[inline]
fn eq(&self, other: &Wrapping<F>) -> bool {
(self.0).eq(&other.0)
}
}
impl<F> Ord for Wrapping<F>
where
F: Fixed,
{
#[inline]
fn cmp(&self, other: &Wrapping<F>) -> Ordering {
(self.0).cmp(&other.0)
}
}
impl<F> PartialOrd<Wrapping<F>> for Wrapping<F>
where
F: Fixed,
{
#[inline]
fn partial_cmp(&self, other: &Wrapping<F>) -> Option<Ordering> {
(self.0).partial_cmp(&other.0)
}
#[inline]
fn lt(&self, other: &Wrapping<F>) -> bool {
(self.0).lt(&other.0)
}
#[inline]
fn le(&self, other: &Wrapping<F>) -> bool {
(self.0).le(&other.0)
}
#[inline]
fn gt(&self, other: &Wrapping<F>) -> bool {
(self.0).gt(&other.0)
}
#[inline]
fn ge(&self, other: &Wrapping<F>) -> bool {
(self.0).ge(&other.0)
}
}
macro_rules! op {
(
$Fixed:ident($Len:ident)::$wrapping:ident,
$Op:ident $op:ident,
$OpAssign:ident $op_assign:ident
) => {
impl<Frac> $Op<Wrapping<$Fixed<Frac>>> for Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
type Output = Wrapping<$Fixed<Frac>>;
#[inline]
fn $op(self, other: Wrapping<$Fixed<Frac>>) -> Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
Wrapping((self.0).$wrapping(other.0))
}
}
impl<'a, Frac> $Op<Wrapping<$Fixed<Frac>>> for &'a Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
type Output = Wrapping<$Fixed<Frac>>;
#[inline]
fn $op(self, other: Wrapping<$Fixed<Frac>>) -> Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
Wrapping((self.0).$wrapping(other.0))
}
}
impl<'a, Frac> $Op<&'a Wrapping<$Fixed<Frac>>> for Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
type Output = Wrapping<$Fixed<Frac>>;
#[inline]
fn $op(self, other: &Wrapping<$Fixed<Frac>>) -> Wrapping<$Fixed<Frac>> {
Wrapping((self.0).$wrapping(other.0))
}
}
impl<'a, 'b, Frac> $Op<&'a Wrapping<$Fixed<Frac>>> for &'b Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
type Output = Wrapping<$Fixed<Frac>>;
#[inline]
fn $op(self, other: &Wrapping<$Fixed<Frac>>) -> Wrapping<$Fixed<Frac>> {
Wrapping((self.0).$wrapping(other.0))
}
}
impl<Frac> $OpAssign<Wrapping<$Fixed<Frac>>> for Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
#[inline]
fn $op_assign(&mut self, other: Wrapping<$Fixed<Frac>>) {
self.0 = (self.0).$wrapping(other.0);
}
}
impl<'a, Frac> $OpAssign<&'a Wrapping<$Fixed<Frac>>> for Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
#[inline]
fn $op_assign(&mut self, other: &Wrapping<$Fixed<Frac>>) {
self.0 = (self.0).$wrapping(other.0);
}
}
};
}
macro_rules! op_bits {
(
$Fixed:ident($Len:ident)::$wrapping:ident,
$Bits:ident,
$Op:ident $op:ident,
$OpAssign:ident $op_assign:ident
) => {
impl<Frac> $Op<$Bits> for Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
type Output = Wrapping<$Fixed<Frac>>;
#[inline]
fn $op(self, other: $Bits) -> Wrapping<$Fixed<Frac>> {
Wrapping((self.0).$wrapping(other))
}
}
impl<'a, Frac> $Op<$Bits> for &'a Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
type Output = Wrapping<$Fixed<Frac>>;
#[inline]
fn $op(self, other: $Bits) -> Wrapping<$Fixed<Frac>> {
Wrapping((self.0).$wrapping(other))
}
}
impl<'a, Frac> $Op<&'a $Bits> for Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
type Output = Wrapping<$Fixed<Frac>>;
#[inline]
fn $op(self, other: &$Bits) -> Wrapping<$Fixed<Frac>> {
Wrapping((self.0).$wrapping(*other))
}
}
impl<'a, 'b, Frac> $Op<&'a $Bits> for &'b Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
type Output = Wrapping<$Fixed<Frac>>;
#[inline]
fn $op(self, other: &$Bits) -> Wrapping<$Fixed<Frac>> {
Wrapping((self.0).$wrapping(*other))
}
}
impl<Frac> $OpAssign<$Bits> for Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
#[inline]
fn $op_assign(&mut self, other: $Bits) {
self.0 = (self.0).$wrapping(other);
}
}
impl<'a, Frac> $OpAssign<&'a $Bits> for Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
#[inline]
fn $op_assign(&mut self, other: &$Bits) {
self.0 = (self.0).$wrapping(*other);
}
}
};
}
macro_rules! op_sh {
(
$Fixed:ident($Len:ident),
$Op:ident $op:ident,
$OpAssign:ident $op_assign:ident
) => {
impl<Frac> $Op<usize> for Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
type Output = Wrapping<$Fixed<Frac>>;
#[inline]
fn $op(self, other: usize) -> Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
Wrapping($Fixed::from_bits(
CoreWrapping((self.0).to_bits()).$op(other).0,
))
}
}
impl<Frac> $OpAssign<usize> for Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
#[inline]
fn $op_assign(&mut self, other: usize) {
self.0 = (self.0).$op(other);
}
}
impl<'a, Frac> $OpAssign<&'a usize> for Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
#[inline]
fn $op_assign(&mut self, other: &usize) {
self.0 = (self.0).$op(*other);
}
}
};
}
macro_rules! ops {
($Fixed:ident($Len:ident, $Bits:ident)) => {
impl<Frac> Neg for Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
type Output = Wrapping<$Fixed<Frac>>;
#[inline]
fn neg(self) -> Wrapping<$Fixed<Frac>> {
Wrapping((self.0).wrapping_neg())
}
}
impl<'a, Frac> Neg for &'a Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
type Output = Wrapping<$Fixed<Frac>>;
#[inline]
fn neg(self) -> Wrapping<$Fixed<Frac>> {
Wrapping((self.0).wrapping_neg())
}
}
op! { $Fixed($Len)::wrapping_add, Add add, AddAssign add_assign }
op! { $Fixed($Len)::wrapping_sub, Sub sub, SubAssign sub_assign }
op! { $Fixed($Len)::wrapping_mul, Mul mul, MulAssign mul_assign }
op! { $Fixed($Len)::wrapping_div, Div div, DivAssign div_assign }
op_bits! { $Fixed($Len)::wrapping_mul_int, $Bits, Mul mul, MulAssign mul_assign }
op_bits! { $Fixed($Len)::wrapping_div_int, $Bits, Div div, DivAssign div_assign }
op_bits! { $Fixed($Len)::wrapping_rem_int, $Bits, Rem rem, RemAssign rem_assign }
impl<Frac> Not for Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
type Output = Wrapping<$Fixed<Frac>>;
#[inline]
fn not(self) -> Wrapping<$Fixed<Frac>> {
Wrapping((self.0).not())
}
}
impl<'a, Frac> Not for &'a Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
type Output = Wrapping<$Fixed<Frac>>;
#[inline]
fn not(self) -> Wrapping<$Fixed<Frac>> {
Wrapping((self.0).not())
}
}
op! { $Fixed($Len)::bitand, BitAnd bitand, BitAndAssign bitand_assign }
op! { $Fixed($Len)::bitor, BitOr bitor, BitOrAssign bitor_assign }
op! { $Fixed($Len)::bitxor, BitXor bitxor, BitXorAssign bitxor_assign }
op_sh! { $Fixed($Len), Shl shl, ShlAssign shl_assign }
op_sh! { $Fixed($Len), Shr shr, ShrAssign shr_assign }
impl<Frac> Sum<Wrapping<$Fixed<Frac>>> for Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
fn sum<I>(iter: I) -> Wrapping<$Fixed<Frac>>
where
I: Iterator<Item = Wrapping<$Fixed<Frac>>>,
{
iter.fold(Wrapping($Fixed::from_bits(0)), Add::add)
}
}
impl<'a, Frac> Sum<&'a Wrapping<$Fixed<Frac>>> for Wrapping<$Fixed<Frac>>
where
Frac: 'a + Unsigned + IsLessOrEqual<$Len, Output = True>,
{
fn sum<I>(iter: I) -> Wrapping<$Fixed<Frac>>
where
I: Iterator<Item = &'a Wrapping<$Fixed<Frac>>>,
{
iter.fold(Wrapping($Fixed::from_bits(0)), Add::add)
}
}
impl<Frac> Product<Wrapping<$Fixed<Frac>>> for Wrapping<$Fixed<Frac>>
where
Frac: Unsigned + IsLessOrEqual<$Len, Output = True>,
{
fn product<I>(mut iter: I) -> Wrapping<$Fixed<Frac>>
where
I: Iterator<Item = Wrapping<$Fixed<Frac>>>,
{
match iter.next() {
None => Wrapping($Fixed::one().unwrap_or_else(|| $Fixed::from_bits(0))),
Some(first) => iter.fold(first, Mul::mul),
}
}
}
impl<'a, Frac> Product<&'a Wrapping<$Fixed<Frac>>> for Wrapping<$Fixed<Frac>>
where
Frac: 'a + Unsigned + IsLessOrEqual<$Len, Output = True>,
{
fn product<I>(mut iter: I) -> Wrapping<$Fixed<Frac>>
where
I: Iterator<Item = &'a Wrapping<$Fixed<Frac>>>,
{
match iter.next() {
None => Wrapping($Fixed::one().unwrap_or_else(|| $Fixed::from_bits(0))),
Some(first) => iter.fold(*first, Mul::mul),
}
}
}
};
}
ops! { FixedI8(U8, i8) }
ops! { FixedI16(U16, i16) }
ops! { FixedI32(U32, i32) }
ops! { FixedI64(U64, i64) }
ops! { FixedI128(U128, i128) }
ops! { FixedU8(U8, u8) }
ops! { FixedU16(U16, u16) }
ops! { FixedU32(U32, u32) }
ops! { FixedU64(U64, u64) }
ops! { FixedU128(U128, u128) }