Skip to content

Commit

Permalink
Implement Num from num-traits (#480)
Browse files Browse the repository at this point in the history
  • Loading branch information
SamWilsn authored Dec 25, 2020
1 parent 935a92c commit da4262d
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 0 deletions.
1 change: 1 addition & 0 deletions ethereum-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ serialize = ["std", "impl-serde", "primitive-types/serde", "ethbloom/serialize"]
arbitrary = ["ethbloom/arbitrary", "fixed-hash/arbitrary", "uint-crate/arbitrary"]
rlp = ["impl-rlp", "ethbloom/rlp", "primitive-types/rlp"]
codec = ["impl-codec", "ethbloom/codec"]
num-traits = ["primitive-types/num-traits"]
2 changes: 2 additions & 0 deletions ethereum-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ mod uint;

pub use ethbloom::{Bloom, BloomRef, Input as BloomInput};
pub use hash::{BigEndianHash, H128, H160, H256, H264, H32, H512, H520, H64};
#[cfg(feature = "num-traits")]
pub use primitive_types::{FromStrRadixErr, FromStrRadixErrKind};
pub use uint::{FromDecStrErr, U128, U256, U512, U64};

pub type Address = H160;
Expand Down
2 changes: 2 additions & 0 deletions primitive-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ fixed-hash = { version = "0.6", path = "../fixed-hash", default-features = false
uint = { version = "0.8.3", path = "../uint", default-features = false }
impl-serde = { version = "0.3.1", path = "impls/serde", default-features = false, optional = true }
impl-codec = { version = "0.4.1", path = "impls/codec", default-features = false, optional = true }
impl-num-traits = { version = "0.1.0", path = "impls/num-traits", default-features = false, optional = true }
impl-rlp = { version = "0.3", path = "impls/rlp", default-features = false, optional = true }
scale-info = { version = "0.4", features = ["derive"], default-features = false, optional = true }

Expand All @@ -26,6 +27,7 @@ codec = ["impl-codec"]
rlp = ["impl-rlp"]
arbitrary = ["fixed-hash/arbitrary", "uint/arbitrary"]
fp-conversion = ["std"]
num-traits = ["impl-num-traits"]

[[test]]
name = "scale_info"
Expand Down
16 changes: 16 additions & 0 deletions primitive-types/impls/num-traits/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "impl-num-traits"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT OR Apache-2.0"
homepage = "https://github.com/paritytech/parity-common"
description = "num-traits implementation for uint."
edition = "2018"

[dependencies]
num-traits = { version = "0.2", default-features = false }
uint = { version = "0.8.5", path = "../../../uint", default-features = false }

[features]
default = ["std"]
std = ["num-traits/std", "uint/std"]
49 changes: 49 additions & 0 deletions primitive-types/impls/num-traits/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2020 Parity Technologies
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! num-traits support for uint.

#![cfg_attr(not(feature = "std"), no_std)]

#[doc(hidden)]
pub use num_traits;

pub use uint::{FromStrRadixErr, FromStrRadixErrKind};

/// Add num-traits support to an integer created by `construct_uint!`.
#[macro_export]
macro_rules! impl_uint_num_traits {
($name: ident, $len: expr) => {
impl $crate::num_traits::identities::Zero for $name {
#[inline]
fn zero() -> Self {
Self::zero()
}

#[inline]
fn is_zero(&self) -> bool {
self.is_zero()
}
}

impl $crate::num_traits::identities::One for $name {
#[inline]
fn one() -> Self {
Self::one()
}
}

impl $crate::num_traits::Num for $name {
type FromStrRadixErr = $crate::FromStrRadixErr;

fn from_str_radix(txt: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
Self::from_str_radix(txt, radix)
}
}
};
}
11 changes: 11 additions & 0 deletions primitive-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use fixed_hash::{construct_fixed_hash, impl_fixed_hash_conversions};
#[cfg(feature = "scale-info")]
use scale_info::TypeInfo;
use uint::{construct_uint, uint_full_mul_reg};
pub use uint::{FromStrRadixErr, FromStrRadixErrKind};

/// Error type for conversion.
#[derive(Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -68,6 +69,16 @@ construct_fixed_hash! {
pub struct H512(64);
}

#[cfg(feature = "num-traits")]
mod num_traits {
use super::*;
use impl_num_traits::impl_uint_num_traits;

impl_uint_num_traits!(U128, 2);
impl_uint_num_traits!(U256, 4);
impl_uint_num_traits!(U512, 8);
}

#[cfg(feature = "impl-serde")]
mod serde {
use super::*;
Expand Down
108 changes: 108 additions & 0 deletions uint/src/uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,102 @@

use core::fmt;

/// A list of error categories encountered when parsing numbers.
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
#[non_exhaustive]
pub enum FromStrRadixErrKind {
/// A character in the input string is not valid for the given radix.
InvalidCharacter,

/// The input length is not valid for the given radix.
InvalidLength,

/// The given radix is not supported.
UnsupportedRadix,
}

#[derive(Debug)]
enum FromStrRadixErrSrc {
Hex(FromHexError),
Dec(FromDecStrErr),
}

impl fmt::Display for FromStrRadixErrSrc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FromStrRadixErrSrc::Dec(d) => write!(f, "{}", d),
FromStrRadixErrSrc::Hex(h) => write!(f, "{}", h),
}
}
}

/// The error type for parsing numbers from strings.
#[derive(Debug)]
pub struct FromStrRadixErr {
kind: FromStrRadixErrKind,
source: Option<FromStrRadixErrSrc>,
}

impl FromStrRadixErr {
#[doc(hidden)]
pub fn unsupported() -> Self {
Self { kind: FromStrRadixErrKind::UnsupportedRadix, source: None }
}

/// Returns the corresponding `FromStrRadixErrKind` for this error.
pub fn kind(&self) -> FromStrRadixErrKind {
self.kind
}
}

impl fmt::Display for FromStrRadixErr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(ref src) = self.source {
return write!(f, "{}", src);
}

match self.kind {
FromStrRadixErrKind::UnsupportedRadix => write!(f, "the given radix is not supported"),
FromStrRadixErrKind::InvalidCharacter => write!(f, "input contains an invalid character"),
FromStrRadixErrKind::InvalidLength => write!(f, "length not supported for radix or type"),
}
}
}

#[cfg(feature = "std")]
impl std::error::Error for FromStrRadixErr {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self.source {
Some(FromStrRadixErrSrc::Dec(ref d)) => Some(d),
Some(FromStrRadixErrSrc::Hex(ref h)) => Some(h),
None => None,
}
}
}

impl From<FromDecStrErr> for FromStrRadixErr {
fn from(e: FromDecStrErr) -> Self {
let kind = match e {
FromDecStrErr::InvalidCharacter => FromStrRadixErrKind::InvalidCharacter,
FromDecStrErr::InvalidLength => FromStrRadixErrKind::InvalidLength,
};

Self { kind, source: Some(FromStrRadixErrSrc::Dec(e)) }
}
}

impl From<FromHexError> for FromStrRadixErr {
fn from(e: FromHexError) -> Self {
let kind = match e.inner {
hex::FromHexError::InvalidHexCharacter { .. } => FromStrRadixErrKind::InvalidCharacter,
hex::FromHexError::InvalidStringLength => FromStrRadixErrKind::InvalidLength,
hex::FromHexError::OddLength => FromStrRadixErrKind::InvalidLength,
};

Self { kind, source: Some(FromStrRadixErrSrc::Hex(e)) }
}
}

/// Conversion from decimal string error
#[derive(Debug, PartialEq)]
pub enum FromDecStrErr {
Expand Down Expand Up @@ -493,6 +589,18 @@ macro_rules! construct_uint {
/// Maximum value.
pub const MAX: $name = $name([u64::max_value(); $n_words]);

/// Converts a string slice in a given base to an integer. Only supports radixes of 10
/// and 16.
pub fn from_str_radix(txt: &str, radix: u32) -> Result<Self, $crate::FromStrRadixErr> {
let parsed = match radix {
10 => Self::from_dec_str(txt)?,
16 => core::str::FromStr::from_str(txt)?,
_ => return Err($crate::FromStrRadixErr::unsupported()),
};

Ok(parsed)
}

/// Convert from a decimal string.
pub fn from_dec_str(value: &str) -> $crate::core_::result::Result<Self, $crate::FromDecStrErr> {
if !value.bytes().all(|b| b >= 48 && b <= 57) {
Expand Down

0 comments on commit da4262d

Please sign in to comment.