cosmwasm_std/math/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
mod conversion;
mod decimal;
mod decimal256;
mod fraction;
mod int128;
mod int256;
mod int512;
mod int64;
mod isqrt;
mod num_consts;
mod signed_decimal;
mod signed_decimal_256;
mod uint128;
mod uint256;
mod uint512;
mod uint64;
pub use decimal::{Decimal, DecimalRangeExceeded};
pub use decimal256::{Decimal256, Decimal256RangeExceeded};
pub use fraction::Fraction;
pub use int128::Int128;
pub use int256::Int256;
pub use int512::Int512;
pub use int64::Int64;
pub use isqrt::Isqrt;
pub use signed_decimal::{SignedDecimal, SignedDecimalRangeExceeded};
pub use signed_decimal_256::{SignedDecimal256, SignedDecimal256RangeExceeded};
pub use uint128::Uint128;
pub use uint256::Uint256;
pub use uint512::Uint512;
pub use uint64::Uint64;
macro_rules! impl_int_serde {
($ty:ty) => {
impl ::serde::Serialize for $ty {
/// Serializes as an integer string using base 10.
///
/// We consistently serialize all `UintXXX` and `IntYYY` types as strings in JSON
/// to ensure the best possible compatibility with clients. E.g. JavaScript and jq
/// only support up to ~53bit numbers without losing precision, making it hard to use
/// serialized `u64`s on other systems than Rust or Go. `Uint64`/`Int64` ensure the full
/// 64 bit range is supported. For larger integers, the use of strings is pretty much the
/// only reasonable way to store them in JSON.
///
/// For binary encodings (notably MessagePack) strings are used too. The reason is that
/// in MessagePack integers are limited to 64 bit and we strive for consistent encoding
/// within the `UintXXX`/`IntYYY` family. Also for small to mid sized values, decimal strings
/// are often more compact than a fixed-length binary encoding.
///
/// ## Examples
///
/// Serialize to JSON:
///
/// ```
/// # use cosmwasm_std::{to_json_vec, Uint64};
/// let value = Uint64::new(17);
/// let serialized = to_json_vec(&value).unwrap();
/// assert_eq!(serialized, b"\"17\"");
/// ```
///
/// Serialize to MessagePack:
///
/// ```
/// # use cosmwasm_std::{to_msgpack_vec, Uint64};
/// let value = Uint64::new(17);
/// let serialized = to_msgpack_vec(&value).unwrap();
/// assert_eq!(serialized, [0b10100000 ^ 2, b'1', b'7']); // string of lengths 2 with value "17"
/// ```
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ::serde::ser::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl<'de> ::serde::Deserialize<'de> for $ty {
/// Deserializes from an integer string using base 10.
///
/// See the [`Serialize` documentation](#method.serialize) for a few more words
/// on the encoding of the `UintXXX`/`IntYYY` family.
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: ::serde::de::Deserializer<'de>,
{
struct IntVisitor;
impl<'de> ::serde::de::Visitor<'de> for IntVisitor {
type Value = $ty;
fn expecting(
&self,
formatter: &mut ::core::fmt::Formatter,
) -> ::core::fmt::Result {
formatter.write_str("string-encoded integer")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: ::serde::de::Error,
{
<_>::try_from(v).map_err(|e| {
E::custom(format_args!("invalid {} '{v}' - {e}", stringify!($t)))
})
}
}
deserializer.deserialize_str(IntVisitor)
}
}
};
}
use impl_int_serde;
#[cfg(test)]
mod tests {
use super::*;
use core::ops::*;
/// A trait that ensures other traits are implemented for our number types
trait AllImpl<'a>:
Add
+ Add<&'a Self>
+ AddAssign
+ AddAssign<&'a Self>
+ Sub
+ Sub<&'a Self>
+ SubAssign
+ SubAssign<&'a Self>
+ Mul
+ Mul<&'a Self>
+ MulAssign
+ MulAssign<&'a Self>
+ Div
+ Div<&'a Self>
+ DivAssign
+ DivAssign<&'a Self>
+ Rem
+ Rem<&'a Self>
+ RemAssign
+ RemAssign<&'a Self>
+ Sized
+ Copy
where
Self: 'a,
{
}
/// A trait that ensures other traits are implemented for our integer types
trait IntImpl<'a>:
AllImpl<'a>
+ Shl<u32>
+ Shl<&'a u32>
+ ShlAssign<u32>
+ ShlAssign<&'a u32>
+ Shr<u32>
+ Shr<&'a u32>
+ ShrAssign<u32>
+ ShrAssign<&'a u32>
+ Not<Output = Self>
+ super::num_consts::NumConsts
{
}
#[allow(dead_code)] // This is used to statically ensure all the integers have a shared set of traits
trait SignedImpl<'a>: IntImpl<'a> + Neg<Output = Self> {}
impl AllImpl<'_> for Uint64 {}
impl AllImpl<'_> for Uint128 {}
impl AllImpl<'_> for Uint256 {}
impl AllImpl<'_> for Uint512 {}
impl AllImpl<'_> for Int64 {}
impl AllImpl<'_> for Int128 {}
impl AllImpl<'_> for Int256 {}
impl AllImpl<'_> for Int512 {}
impl IntImpl<'_> for Int64 {}
impl IntImpl<'_> for Int128 {}
impl IntImpl<'_> for Int256 {}
impl IntImpl<'_> for Int512 {}
impl IntImpl<'_> for Uint64 {}
impl IntImpl<'_> for Uint128 {}
impl IntImpl<'_> for Uint256 {}
impl IntImpl<'_> for Uint512 {}
impl AllImpl<'_> for Decimal {}
impl AllImpl<'_> for Decimal256 {}
impl SignedImpl<'_> for Int64 {}
impl SignedImpl<'_> for Int128 {}
impl SignedImpl<'_> for Int256 {}
impl SignedImpl<'_> for Int512 {}
}