Skip to content
Open
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/target/
Cargo.lock
*.swp
.idea/
19 changes: 15 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
[package]
name = "rust-gmp"
version = "0.5.0"
version = "0.5.1"
authors = [ "thestinger <[email protected]>", "Bartłomiej Kamiński <[email protected]>" ]
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" }
5 changes: 5 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
78 changes: 75 additions & 3 deletions src/mpz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -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;
Expand Down Expand Up @@ -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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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<D>(deserializer: D) -> Result<Mpz, D::Error>
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<E: de::Error>(self, s: &str) -> Result<Mpz, E> {
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
Expand Down Expand Up @@ -1016,4 +1089,3 @@ impl One for Mpz {
Mpz::one()
}
}

14 changes: 14 additions & 0 deletions src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<i64>::from(1000);
Expand Down Expand Up @@ -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::<i64>::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 {
Expand Down