diff --git a/.gitignore b/.gitignore index 31cb256..91d9203 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target/ Cargo.lock *.swp +.idea/ diff --git a/Cargo.toml b/Cargo.toml index b2f84b6..87d0395 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,16 +1,27 @@ [package] name = "rust-gmp" -version = "0.5.0" +version = "0.5.1" authors = [ "thestinger ", "Bartłomiej Kamiński " ] description = "Rust bindings for GMP" -repository = "https://github.com/fizyk20/rust-gmp" -documentation = "https://docs.rs/rust-gmp" +repository = "https://github.com/ZenGo-X/rust-gmp" +documentation = "https://docs.rs/rust-gmp-kzen" license = "MIT" keywords = [ "gmp", "multi", "precision", "arithmetic", "bignum" ] [lib] name = "gmp" +[features] +default = [] + +# Feature for enabling de/serialization of Mpz +serde_support = ["serde"] + [dependencies] libc = "~0.2" -num-traits = "0.1" +num-traits = "0.2" + +serde = { version = "1.0", optional = true, features = ["derive"] } + +[dev-dependencies] +serde_json = { version = "1.0" } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 44b1ca1..f806815 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,11 @@ extern crate libc; extern crate num_traits; +#[cfg(feature="serde")] +extern crate serde; +#[cfg(all(test, feature="serde"))] +extern crate serde_json; + mod ffi; pub mod mpz; pub mod mpq; diff --git a/src/mpz.rs b/src/mpz.rs index 6226744..08552f6 100644 --- a/src/mpz.rs +++ b/src/mpz.rs @@ -12,6 +12,15 @@ use std::ffi::CString; use std::{u32, i32}; use num_traits::{Zero, One}; +#[cfg(feature="serde")] +use serde::ser::{Serialize, Serializer}; +#[cfg(feature="serde")] +use serde::de::{Visitor}; +#[cfg(feature="serde")] +use serde::de; +#[cfg(feature="serde")] +use serde::{Deserialize, Deserializer}; + use ffi::*; #[repr(C)] @@ -36,6 +45,7 @@ extern "C" { fn __gmpz_init_set_str(rop: mpz_ptr, s: *const c_char, base: c_int) -> c_int; fn __gmpz_clear(x: mpz_ptr); fn __gmpz_realloc2(x: mpz_ptr, n: mp_bitcnt_t); + fn __gmpz_size(x: mpz_ptr) -> c_int; fn __gmpz_set(rop: mpz_ptr, op: mpz_srcptr); fn __gmpz_set_str(rop: mpz_ptr, s: *const c_char, base: c_int) -> c_int; fn __gmpz_get_str(s: *mut c_char, base: c_int, op: mpz_srcptr) -> *mut c_char; @@ -101,11 +111,74 @@ pub struct Mpz { mpz: mpz_struct, } +#[cfg(feature="serde")] +const HEX_RADIX : u8 = 16; + +#[cfg(feature="serde")] +impl Serialize for Mpz { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&self.to_str_radix(HEX_RADIX)) + } +} + +#[cfg(feature="serde")] +struct MpzVisitor; + +#[cfg(feature="serde")] +impl<'de> Deserialize<'de> for Mpz { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(MpzVisitor) + } +} + +#[cfg(feature="serde")] +impl<'de> Visitor<'de> for MpzVisitor { + type Value = Mpz; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("BigInt") + } + + fn visit_str(self, s: &str) -> Result { + Ok(Mpz::from_str_radix(s, HEX_RADIX).expect("Failed in serde")) + } +} + unsafe impl Send for Mpz { } unsafe impl Sync for Mpz { } - +use std::sync::atomic; impl Drop for Mpz { - fn drop(&mut self) { unsafe { __gmpz_clear(&mut self.mpz) } } + fn drop(&mut self) { + unsafe { + let size_limbs = __gmpz_size(&mut self.mpz); + let dst = self.mpz._mp_d as *mut c_int; + for i in 0..size_limbs{ + /* + * A note on safety of this: + * + * 1. In gmp source the mp_limb_t is defined as unsigned long so c_int will never + * be more than that on any platform. + * + * 2. Memory for the array(_mp_d) is guaranteed to be allocated by gmp in limb sizes. + * So we can be sure that we are not writing what we should not. + * + * Also I think we should be having something in the gmp library itself to do this kind of a thing. + * The process for that is in flight. If that is accepted we can use that here. + */ + std::ptr::write_volatile(dst.add(i as usize) as *mut c_int, 0); + } + __gmpz_clear(&mut self.mpz); + } + + atomic::fence(atomic::Ordering::SeqCst); + atomic::compiler_fence(atomic::Ordering::SeqCst); + } } /// The result of running probab_prime @@ -1016,4 +1089,3 @@ impl One for Mpz { Mpz::one() } } - diff --git a/src/test.rs b/src/test.rs index 3af1382..fe22340 100644 --- a/src/test.rs +++ b/src/test.rs @@ -25,6 +25,9 @@ mod mpz { use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; + #[cfg(feature="serde")] + use serde_json; + #[test] fn test_set() { let mut x: Mpz = From::::from(1000); @@ -570,6 +573,17 @@ mod mpz { assert_eq!(five.sign(), Sign::Positive); assert_eq!(minus_five.sign(), Sign::Negative); } + + #[cfg(feature="serde")] + #[test] + fn test_serde() { + let one: Mpz = From::::from(1); + assert_eq!(serde_json::to_string(&one).unwrap(), "\"1\""); + + let s_one = "\"1\""; + let o_one : Mpz = serde_json::from_str(&s_one).unwrap(); + assert_eq!(o_one, one); + } } mod rand {