use bincode::de::{BorrowDecoder, Decoder};
use bincode::enc::Encoder;
use bincode::error::{DecodeError, EncodeError};
use bincode::{BorrowDecode, Decode, Encode};
use num_bigint::BigUint;
#[cfg(feature = "json")]
use {
crate::serde::biguint_serde,
serde::{Deserialize, Serialize},
};
#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "json", serde(transparent))]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
pub struct BigNumber(#[cfg_attr(feature = "json", serde(with = "biguint_serde"))] pub BigUint);
impl BigNumber {
pub fn zero() -> BigNumber {
BigUint::from(0u64).into()
}
}
impl<T> From<T> for BigNumber
where
BigUint: From<T>,
{
fn from(v: T) -> Self {
BigNumber(BigUint::from(v))
}
}
impl Encode for BigNumber {
fn encode<E: Encoder>(&self, encoder: &mut E) -> std::result::Result<(), EncodeError> {
self.0.to_bytes_le().encode(encoder)
}
}
impl<Context> Decode<Context> for BigNumber {
fn decode<D: Decoder>(decoder: &mut D) -> std::result::Result<Self, DecodeError> {
let bytes = Vec::<u8>::decode(decoder)?;
Ok(BigNumber(BigUint::from_bytes_le(&bytes)))
}
}
impl<'de, Context> BorrowDecode<'de, Context> for BigNumber {
fn borrow_decode<D: BorrowDecoder<'de>>(
decoder: &mut D,
) -> std::result::Result<Self, DecodeError> {
Self::decode(decoder)
}
}
impl std::fmt::Display for BigNumber {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0.to_str_radix(10))
}
}
#[cfg(test)]
mod tests {
use super::*;
fn encode_decode(value: BigNumber) {
let bytes = bincode::encode_to_vec(&value, bincode::config::standard()).unwrap();
let (decoded, _): (BigNumber, _) =
bincode::decode_from_slice(&bytes, bincode::config::standard()).unwrap();
assert_eq!(decoded, value);
}
#[test]
fn bincode_encode_decode_raw_bytes() {
encode_decode(BigNumber::zero());
encode_decode(BigNumber::from(1u64));
encode_decode(BigNumber::from(u64::MAX));
let wide = BigUint::parse_bytes(b"123456789012345678901234567890123456789", 10).unwrap();
encode_decode(BigNumber(wide));
}
#[test]
fn bincode_encodes_little_endian_magnitude() {
let bytes =
bincode::encode_to_vec(BigNumber::from(258u64), bincode::config::standard()).unwrap();
assert_eq!(bytes, vec![2, 2, 1]);
}
}