From 64f50ad714e43df16ac04b6867081afc6269ec9b Mon Sep 17 00:00:00 2001 From: Boyu Yang Date: Mon, 25 Mar 2019 19:01:44 +0800 Subject: [PATCH] Add readable constructors via proc-macro. --- .../fixed_hash/core/internal/public_conv.rs | 5 +- .../fixed_uint/core/internal/public_conv.rs | 5 +- fixed-hash-tests/tests/constructor.rs | 29 +++++ fixed-hash/Cargo.toml | 16 ++- fixed-hash/core/Cargo.toml | 21 ++++ fixed-hash/core/src/lib.rs | 55 ++++++++++ fixed-hash/{ => core}/src/tools.rs | 14 +-- fixed-hash/hack/Cargo.toml | 21 ++++ fixed-hash/hack/src/lib.rs | 66 ++++++++++++ fixed-hash/src/lib.rs | 59 +++-------- fixed-uint-tests/tests/constructor.rs | 100 ++++++++++++++++++ fixed-uint/Cargo.toml | 14 ++- fixed-uint/core/Cargo.toml | 18 ++++ fixed-uint/core/src/lib.rs | 42 ++++++++ fixed-uint/hack/Cargo.toml | 21 ++++ fixed-uint/hack/src/lib.rs | 60 +++++++++++ fixed-uint/src/lib.rs | 50 +++------ 17 files changed, 492 insertions(+), 104 deletions(-) create mode 100644 fixed-hash-tests/tests/constructor.rs create mode 100644 fixed-hash/core/Cargo.toml create mode 100644 fixed-hash/core/src/lib.rs rename fixed-hash/{ => core}/src/tools.rs (75%) create mode 100644 fixed-hash/hack/Cargo.toml create mode 100644 fixed-hash/hack/src/lib.rs create mode 100644 fixed-uint-tests/tests/constructor.rs create mode 100644 fixed-uint/core/Cargo.toml create mode 100644 fixed-uint/core/src/lib.rs create mode 100644 fixed-uint/hack/Cargo.toml create mode 100644 fixed-uint/hack/src/lib.rs diff --git a/constructor/src/fixed_hash/core/internal/public_conv.rs b/constructor/src/fixed_hash/core/internal/public_conv.rs index 9660837..dd40d42 100644 --- a/constructor/src/fixed_hash/core/internal/public_conv.rs +++ b/constructor/src/fixed_hash/core/internal/public_conv.rs @@ -107,7 +107,10 @@ impl HashConstructor { } ); self.attach_common(part); - let part = quote!(#[fail(display = "failed to parse from string {}", _0)] + let part = quote!(#[fail( + display = "failed to parse from string since {}", + _0 + )] FromStr( #[fail(cause)] FromStrError diff --git a/constructor/src/fixed_uint/core/internal/public_conv.rs b/constructor/src/fixed_uint/core/internal/public_conv.rs index 6b9c255..63795ba 100644 --- a/constructor/src/fixed_uint/core/internal/public_conv.rs +++ b/constructor/src/fixed_uint/core/internal/public_conv.rs @@ -282,7 +282,10 @@ impl UintConstructor { } ); self.attach_common(part); - let part = quote!(#[fail(display = "failed to parse from string {}", _0)] + let part = quote!(#[fail( + display = "failed to parse from string since {}", + _0 + )] FromStr( #[fail(cause)] FromStrError diff --git a/fixed-hash-tests/tests/constructor.rs b/fixed-hash-tests/tests/constructor.rs new file mode 100644 index 0000000..d1548dc --- /dev/null +++ b/fixed-hash-tests/tests/constructor.rs @@ -0,0 +1,29 @@ +// Copyright 2018-2019 Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use nfhash::{h128, h4096, H128, H4096}; +use std::str::FromStr; + +const H64MAX: H4096 = h4096!("0x_ffff_ffff_ffff_ffff"); + +#[test] +fn constructor() { + { + let x1 = h128!("0x123456789abcdef"); + let x2 = h128!("0x00000000000000000123456789abcdef"); + let y = H128::from_str("00000000000000000123456789abcdef").unwrap(); + assert_eq!(x1, y); + assert_eq!(x2, y); + } + { + let x = h4096!("0x_ffff_ffff_ffff_ffff"); + let y = H4096::from_trimmed_hex_str("ffffffffffffffff").unwrap(); + assert_eq!(x, y); + assert_eq!(H64MAX, y); + } +} diff --git a/fixed-hash/Cargo.toml b/fixed-hash/Cargo.toml index eb4dda2..8253ee2 100644 --- a/fixed-hash/Cargo.toml +++ b/fixed-hash/Cargo.toml @@ -11,20 +11,16 @@ categories = ["algorithms", "data-structures"] license = "Apache-2.0 OR MIT" [dependencies] -numext-constructor = { version = "~0.1.2", path = "../constructor" } -nfuint = { package = "numext-fixed-uint", version = "~0.1.2", path = "../fixed-uint" } -failure = "~0.1" -rand = { version = "~0.5", optional = true } -heapsize = { version = "~0.4", optional = true } -serde = { version = "~1.0", optional = true } -faster-hex = { version = "~0.1", optional = true } +numext-fixed-hash-core = { path = "core" } +numext-fixed-hash-hack = { path = "hack" } +proc-macro-hack = "~0.5" [features] default = [] support_all = ["support_rand", "support_heapsize", "support_serde"] -support_rand = ["rand", "nfuint/support_rand"] -support_heapsize = ["heapsize", "nfuint/support_heapsize"] -support_serde = ["serde", "faster-hex", "nfuint/support_serde"] +support_rand = ["numext-fixed-hash-core/support_rand", "numext-fixed-hash-hack/support_rand"] +support_heapsize = ["numext-fixed-hash-core/support_heapsize", "numext-fixed-hash-hack/support_heapsize"] +support_serde = ["numext-fixed-hash-core/support_serde", "numext-fixed-hash-hack/support_serde"] [badges] travis-ci = { repository = "cryptape/rust-numext" } diff --git a/fixed-hash/core/Cargo.toml b/fixed-hash/core/Cargo.toml new file mode 100644 index 0000000..f6c34ae --- /dev/null +++ b/fixed-hash/core/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "numext-fixed-hash-core" +version = "0.1.2" +authors = ["Cryptape Technologies "] +edition = "2018" + +[dependencies] +numext-constructor = { version = "~0.1.2", path = "../../constructor" } +failure = "~0.1" +rand = { version = "~0.5", optional = true } +heapsize = { version = "~0.4", optional = true } +serde = { version = "~1.0", optional = true } +faster-hex = { version = "~0.1", optional = true } +numext-fixed-uint = { version = "~0.1.2", path = "../../fixed-uint" } + +[features] +default = [] +support_all = ["support_rand", "support_heapsize", "support_serde"] +support_rand = ["rand", "numext-fixed-uint/support_rand"] +support_heapsize = ["heapsize", "numext-fixed-uint/support_heapsize"] +support_serde = ["serde", "faster-hex", "numext-fixed-uint/support_serde"] diff --git a/fixed-hash/core/src/lib.rs b/fixed-hash/core/src/lib.rs new file mode 100644 index 0000000..c3acca3 --- /dev/null +++ b/fixed-hash/core/src/lib.rs @@ -0,0 +1,55 @@ +// Copyright 2018-2019 Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use failure::Fail; + +#[macro_use] +mod tools; + +numext_constructor::construct_fixed_hashes!( + H128 { + size = 128, + }, + H160 { + size = 160, + }, + H224 { + size = 224, + }, + H256 { + size = 256, + }, + H384 { + size = 384, + }, + H512 { + size = 512, + }, + H520 { + size = 520, + }, + H1024 { + size = 1024, + }, + H2048 { + size = 2048, + }, + H4096 { + size = 4096, + }, +); + +convert_between!(U128, H128, 16); +convert_between!(U160, H160, 20); +convert_between!(U224, H224, 28); +convert_between!(U256, H256, 32); +convert_between!(U384, H384, 48); +convert_between!(U512, H512, 64); +convert_between!(U1024, H1024, 128); +convert_between!(U2048, H2048, 256); +convert_between!(U4096, H4096, 512); diff --git a/fixed-hash/src/tools.rs b/fixed-hash/core/src/tools.rs similarity index 75% rename from fixed-hash/src/tools.rs rename to fixed-hash/core/src/tools.rs index 0c5df81..7bbfaea 100644 --- a/fixed-hash/src/tools.rs +++ b/fixed-hash/core/src/tools.rs @@ -8,9 +8,9 @@ macro_rules! convert_between { ($uint:ident, $hash:ident, $bytes_size:expr) => { - impl<'a> From<&'a nfuint::$uint> for $hash { + impl<'a> From<&'a numext_fixed_uint::$uint> for $hash { #[inline] - fn from(u: &nfuint::$uint) -> Self { + fn from(u: &numext_fixed_uint::$uint) -> Self { let mut ret = [0u8; $bytes_size]; u.into_big_endian(&mut ret).unwrap_or_else(|e| { panic!( @@ -23,16 +23,16 @@ macro_rules! convert_between { ret.into() } } - impl From for $hash { + impl From for $hash { #[inline] - fn from(u: nfuint::$uint) -> Self { + fn from(u: numext_fixed_uint::$uint) -> Self { (&u).into() } } - impl<'a> From<&'a $hash> for nfuint::$uint { + impl<'a> From<&'a $hash> for numext_fixed_uint::$uint { #[inline] fn from(h: &$hash) -> Self { - nfuint::$uint::from_big_endian(h.as_bytes()).unwrap_or_else(|e| { + numext_fixed_uint::$uint::from_big_endian(h.as_bytes()).unwrap_or_else(|e| { panic!( "failed to convert from {} to {}: {}", stringify!($hash), @@ -42,7 +42,7 @@ macro_rules! convert_between { }) } } - impl From<$hash> for nfuint::$uint { + impl From<$hash> for numext_fixed_uint::$uint { #[inline] fn from(h: $hash) -> Self { (&h).into() diff --git a/fixed-hash/hack/Cargo.toml b/fixed-hash/hack/Cargo.toml new file mode 100644 index 0000000..b2bf6d8 --- /dev/null +++ b/fixed-hash/hack/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "numext-fixed-hash-hack" +version = "0.1.2" +authors = ["Cryptape Technologies "] +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +numext-fixed-hash-core = { path = "../core" } +proc-macro-hack = "~0.5" +syn = { version = "~0.15", features = ["extra-traits"] } +quote = "~0.6" +proc-macro2 = "~0.4" + +[features] +default = [] +support_rand = ["numext-fixed-hash-core/support_rand"] +support_heapsize = ["numext-fixed-hash-core/support_heapsize"] +support_serde = ["numext-fixed-hash-core/support_serde"] diff --git a/fixed-hash/hack/src/lib.rs b/fixed-hash/hack/src/lib.rs new file mode 100644 index 0000000..ce4c580 --- /dev/null +++ b/fixed-hash/hack/src/lib.rs @@ -0,0 +1,66 @@ +// Copyright 2018-2019 Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate proc_macro; + +use numext_fixed_hash_core as nfhash; +use proc_macro_hack::proc_macro_hack; +use quote::quote; +use syn::parse_macro_input; + +macro_rules! impl_hack { + ($(($name:ident, $type:ident),)+) => { + $(impl_hack!($name, $type);)+ + }; + ($(($name:ident, $type:ident)),+) => { + $(impl_hack!($name, $type);)+ + }; + ($name:ident, $type:ident) => { + #[proc_macro_hack] + pub fn $name(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = parse_macro_input!(input as syn::LitStr); + let expanded = { + let input = input.value().replace("_", ""); + if &input[..2] != "0x" { + panic!("Input has to be a hexadecimal string with 0x-prefix."); + }; + let input_str = &input[2..]; + let value = match &input_str[..1] { + "0" => { + nfhash::$type::from_hex_str(input_str) + }, + _ => { + nfhash::$type::from_trimmed_hex_str(input_str) + }, + } + .unwrap_or_else(|err| { + panic!("Failed to parse the input hexadecimal string: {}", err); + }); + let eval_str = format!("{:?}", value); + let eval_ts: proc_macro2::TokenStream = eval_str.parse().unwrap_or_else(|_| { + panic!("Failed to parse the string \"{}\" to TokenStream.", eval_str); + }); + quote!(#eval_ts) + }; + expanded.into() + } + }; +} + +impl_hack!( + (h128, H128), + (h160, H160), + (h224, H224), + (h256, H256), + (h384, H384), + (h512, H512), + (h520, H520), + (h1024, H1024), + (h2048, H2048), + (h4096, H4096), +); diff --git a/fixed-hash/src/lib.rs b/fixed-hash/src/lib.rs index 500b4c6..c38e734 100644 --- a/fixed-hash/src/lib.rs +++ b/fixed-hash/src/lib.rs @@ -6,50 +6,21 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[macro_use] -mod tools; +use proc_macro_hack::proc_macro_hack; -use failure::Fail; +pub use numext_fixed_hash_core::*; -numext_constructor::construct_fixed_hashes!( - H128 { - size = 128, - }, - H160 { - size = 160, - }, - H224 { - size = 224, - }, - H256 { - size = 256, - }, - H384 { - size = 384, - }, - H512 { - size = 512, - }, - H520 { - size = 520, - }, - H1024 { - size = 1024, - }, - H2048 { - size = 2048, - }, - H4096 { - size = 4096, - }, -); +macro_rules! reexport { + ([$($name:ident,)+]) => { + $(reexport!($name);)+ + }; + ([$($name:ident),+]) => { + $(reexport!($name);)+ + }; + ($name:ident) => { + #[proc_macro_hack] + pub use numext_fixed_hash_hack::$name; + }; +} -convert_between!(U128, H128, 16); -convert_between!(U160, H160, 20); -convert_between!(U224, H224, 28); -convert_between!(U256, H256, 32); -convert_between!(U384, H384, 48); -convert_between!(U512, H512, 64); -convert_between!(U1024, H1024, 128); -convert_between!(U2048, H2048, 256); -convert_between!(U4096, H4096, 512); +reexport!([h128, h160, h224, h256, h384, h512, h520, h1024, h2048, h4096]); diff --git a/fixed-uint-tests/tests/constructor.rs b/fixed-uint-tests/tests/constructor.rs new file mode 100644 index 0000000..82c91de --- /dev/null +++ b/fixed-uint-tests/tests/constructor.rs @@ -0,0 +1,100 @@ +// Copyright 2018-2019 Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use nfuint::{u128, u256, u4096, U128, U256, U4096}; + +const U128_100: U128 = u128!("100"); + +#[test] +fn constructor() { + { + let x1 = u128!("0b110_0100"); + let x2 = u128!("0o144"); + let x3 = u128!("0x64"); + let y = U128::from(100u8); + assert_eq!(x1, y); + assert_eq!(x2, y); + assert_eq!(x3, y); + assert_eq!(U128_100, y); + } + { + let x = u4096!("0x_ab_cdef"); + let y = U4096([ + 0x00ab_cdef, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ]); + assert_eq!(x, y); + } + { + let x = u256!("100_000_000_000_000_000_000"); + let y = U256([0x6bc7_5e2d_6310_0000, 0x5, 0, 0]); + assert_eq!(x, y); + } +} diff --git a/fixed-uint/Cargo.toml b/fixed-uint/Cargo.toml index 884b323..0f9aa30 100644 --- a/fixed-uint/Cargo.toml +++ b/fixed-uint/Cargo.toml @@ -11,18 +11,16 @@ categories = ["algorithms", "data-structures"] license = "Apache-2.0 OR MIT" [dependencies] -numext-constructor = { version = "~0.1.2", path = "../constructor" } -failure = "~0.1" -rand = { version = "~0.5", optional = true } -heapsize = { version = "~0.4", optional = true } -serde = { version = "~1.0", optional = true } +numext-fixed-uint-core = { path = "core" } +numext-fixed-uint-hack = { path = "hack" } +proc-macro-hack = "~0.5" [features] default = [] support_all = ["support_rand", "support_heapsize", "support_serde"] -support_rand = ["rand"] -support_heapsize = ["heapsize"] -support_serde = ["serde"] +support_rand = ["numext-fixed-uint-core/support_rand", "numext-fixed-uint-hack/support_rand"] +support_heapsize = ["numext-fixed-uint-core/support_heapsize", "numext-fixed-uint-hack/support_heapsize"] +support_serde = ["numext-fixed-uint-core/support_serde", "numext-fixed-uint-hack/support_serde"] [badges] travis-ci = { repository = "cryptape/rust-numext" } diff --git a/fixed-uint/core/Cargo.toml b/fixed-uint/core/Cargo.toml new file mode 100644 index 0000000..7ecd8e1 --- /dev/null +++ b/fixed-uint/core/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "numext-fixed-uint-core" +version = "0.1.2" +authors = ["Cryptape Technologies "] +edition = "2018" + +[dependencies] +numext-constructor = { version = "~0.1.2", path = "../../constructor" } +failure = "~0.1" +rand = { version = "~0.5", optional = true } +heapsize = { version = "~0.4", optional = true } +serde = { version = "~1.0", optional = true } + +[features] +default = [] +support_rand = ["rand"] +support_heapsize = ["heapsize"] +support_serde = ["serde"] diff --git a/fixed-uint/core/src/lib.rs b/fixed-uint/core/src/lib.rs new file mode 100644 index 0000000..c3f88a8 --- /dev/null +++ b/fixed-uint/core/src/lib.rs @@ -0,0 +1,42 @@ +// Copyright 2018-2019 Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use failure::Fail; + +numext_constructor::construct_fixed_uints!( + U128 { + size = 128, + }, + U160 { + size = 160, + }, + U224 { + size = 224, + }, + U256 { + size = 256, + }, + U384 { + size = 384, + }, + U512 { + size = 512, + }, + U520 { + size = 520, + }, + U1024 { + size = 1024, + }, + U2048 { + size = 2048, + }, + U4096 { + size = 4096, + }, +); diff --git a/fixed-uint/hack/Cargo.toml b/fixed-uint/hack/Cargo.toml new file mode 100644 index 0000000..726cf74 --- /dev/null +++ b/fixed-uint/hack/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "numext-fixed-uint-hack" +version = "0.1.2" +authors = ["Cryptape Technologies "] +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +numext-fixed-uint-core = { path = "../core" } +proc-macro-hack = "~0.5" +syn = { version = "~0.15", features = ["extra-traits"] } +quote = "~0.6" +proc-macro2 = "~0.4" + +[features] +default = [] +support_rand = ["numext-fixed-uint-core/support_rand"] +support_heapsize = ["numext-fixed-uint-core/support_heapsize"] +support_serde = ["numext-fixed-uint-core/support_serde"] diff --git a/fixed-uint/hack/src/lib.rs b/fixed-uint/hack/src/lib.rs new file mode 100644 index 0000000..657db78 --- /dev/null +++ b/fixed-uint/hack/src/lib.rs @@ -0,0 +1,60 @@ +// Copyright 2018-2019 Cryptape Technologies LLC. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate proc_macro; + +use numext_fixed_uint_core as nfuint; +use proc_macro_hack::proc_macro_hack; +use quote::quote; +use syn::parse_macro_input; + +macro_rules! impl_hack { + ($(($name:ident, $type:ident),)+) => { + $(impl_hack!($name, $type);)+ + }; + ($(($name:ident, $type:ident)),+) => { + $(impl_hack!($name, $type);)+ + }; + ($name:ident, $type:ident) => { + #[proc_macro_hack] + pub fn $name(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = parse_macro_input!(input as syn::LitStr); + let expanded = { + let input = input.value().replace("_", ""); + let (value_result, input_type) = match &input[..2] { + "0b" => (nfuint::$type::from_bin_str(&input[2..]), "binary"), + "0o" => (nfuint::$type::from_oct_str(&input[2..]), "octal"), + "0x" => (nfuint::$type::from_hex_str(&input[2..]), "hexadecimal"), + _ => (nfuint::$type::from_dec_str(&input), "decimal"), + }; + let value = value_result.unwrap_or_else(|err| { + panic!("Failed to parse the input {} string: {}", input_type, err); + }); + let eval_str = format!("{:?}", value); + let eval_ts: proc_macro2::TokenStream = eval_str.parse().unwrap_or_else(|_| { + panic!("Failed to parse the string [{}] to TokenStream.", eval_str); + }); + quote!(#eval_ts) + }; + expanded.into() + } + }; +} + +impl_hack!( + (u128, U128), + (u160, U160), + (u224, U224), + (u256, U256), + (u384, U384), + (u512, U512), + (u520, U520), + (u1024, U1024), + (u2048, U2048), + (u4096, U4096), +); diff --git a/fixed-uint/src/lib.rs b/fixed-uint/src/lib.rs index c3f88a8..1fa59ea 100644 --- a/fixed-uint/src/lib.rs +++ b/fixed-uint/src/lib.rs @@ -6,37 +6,21 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use failure::Fail; +use proc_macro_hack::proc_macro_hack; -numext_constructor::construct_fixed_uints!( - U128 { - size = 128, - }, - U160 { - size = 160, - }, - U224 { - size = 224, - }, - U256 { - size = 256, - }, - U384 { - size = 384, - }, - U512 { - size = 512, - }, - U520 { - size = 520, - }, - U1024 { - size = 1024, - }, - U2048 { - size = 2048, - }, - U4096 { - size = 4096, - }, -); +pub use numext_fixed_uint_core::*; + +macro_rules! reexport { + ([$($name:ident,)+]) => { + $(reexport!($name);)+ + }; + ([$($name:ident),+]) => { + $(reexport!($name);)+ + }; + ($name:ident) => { + #[proc_macro_hack] + pub use numext_fixed_uint_hack::$name; + }; +} + +reexport!([u128, u160, u224, u256, u384, u512, u520, u1024, u2048, u4096]);