diff --git a/Cargo.toml b/Cargo.toml index 1c7449b..d375662 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,5 +17,9 @@ name = "lmdb" [dependencies.lmdb-sys] path = "lmdb-sys" -[dependencies.bitflags] -version = "*" +[dependencies] +bitflags = "*" + +[dev-dependencies] +tempdir = "*" +rand = "*" diff --git a/lmdb-sys/build.rs b/lmdb-sys/build.rs index 5be0be0..2206e23 100644 --- a/lmdb-sys/build.rs +++ b/lmdb-sys/build.rs @@ -3,7 +3,6 @@ extern crate "pkg-config" as pkg_config; extern crate gcc; -use std::default::Default; use std::env; use std::path::PathBuf; @@ -22,7 +21,6 @@ fn main() { if !pkg_config::find_library("liblmdb").is_ok() { gcc::compile_library("liblmdb.a", - &Default::default(), &[(*mdb).to_str().unwrap(), (*midl).to_str().unwrap()]); } diff --git a/src/cursor.rs b/src/cursor.rs index f6b7f9b..3816655 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -1,16 +1,15 @@ use libc::{c_void, size_t, c_uint}; use std::{mem, ptr, raw}; -use std::marker; - -use ffi; +use std::marker::{PhantomData, PhantomFn}; use database::Database; use error::{LmdbResult, lmdb_result, LmdbError}; +use ffi; use flags::WriteFlags; use transaction::Transaction; /// An LMDB cursor. -pub trait Cursor<'txn> { +pub trait Cursor<'txn> : PhantomFn<(), &'txn [u8]> { /// Returns a raw pointer to the underlying LMDB cursor. /// /// The caller **must** ensure that the pointer is not used after the lifetime of the cursor. @@ -102,7 +101,7 @@ impl<'txn, T> CursorExt<'txn> for T where T: Cursor<'txn> {} /// A read-only cursor for navigating the items within a database. pub struct RoCursor<'txn> { cursor: *mut ffi::MDB_cursor, - _marker: marker::ContravariantLifetime<'txn>, + _marker: PhantomData &'txn ()>, } impl <'txn> Cursor<'txn> for RoCursor<'txn> { @@ -131,7 +130,7 @@ impl <'txn> RoCursor<'txn> { unsafe { try!(lmdb_result(ffi::mdb_cursor_open(txn.txn(), db.dbi(), &mut cursor))); } Ok(RoCursor { cursor: cursor, - _marker: marker::ContravariantLifetime::<'txn>, + _marker: PhantomData, }) } } @@ -139,7 +138,7 @@ impl <'txn> RoCursor<'txn> { /// A read-only cursor for navigating items within a database. pub struct RwCursor<'txn> { cursor: *mut ffi::MDB_cursor, - _marker: marker::ContravariantLifetime<'txn>, + _marker: PhantomData &'txn ()>, } impl <'txn> Cursor<'txn> for RwCursor<'txn> { @@ -166,10 +165,7 @@ impl <'txn> RwCursor<'txn> { pub fn new(txn: &'txn Transaction, db: Database) -> LmdbResult> { let mut cursor: *mut ffi::MDB_cursor = ptr::null_mut(); unsafe { try!(lmdb_result(ffi::mdb_cursor_open(txn.txn(), db.dbi(), &mut cursor))); } - Ok(RwCursor { - cursor: cursor, - _marker: marker::ContravariantLifetime::<'txn>, - }) + Ok(RwCursor { cursor: cursor, _marker: PhantomData }) } /// Puts a key/data pair into the database. The cursor will be positioned at the new data item, @@ -224,13 +220,14 @@ pub struct Iter<'txn> { cursor: *mut ffi::MDB_cursor, op: c_uint, next_op: c_uint, + _marker: PhantomData, } impl <'txn> Iter<'txn> { /// Creates a new iterator backed by the given cursor. fn new<'t>(cursor: *mut ffi::MDB_cursor, op: c_uint, next_op: c_uint) -> Iter<'t> { - Iter { cursor: cursor, op: op, next_op: next_op } + Iter { cursor: cursor, op: op, next_op: next_op, _marker: PhantomData } } } @@ -263,13 +260,14 @@ impl <'txn> Iterator for Iter<'txn> { pub struct IterDup<'txn> { cursor: *mut ffi::MDB_cursor, op: c_uint, + _marker: PhantomData, } impl <'txn> IterDup<'txn> { /// Creates a new iterator backed by the given cursor. fn new<'t>(cursor: *mut ffi::MDB_cursor, op: c_uint) -> IterDup<'t> { - IterDup { cursor: cursor, op: op} + IterDup { cursor: cursor, op: op, _marker: PhantomData } } } @@ -305,12 +303,13 @@ mod test { use environment::*; use flags::*; use super::*; + use tempdir; use test_utils::*; use transaction::*; #[test] fn test_get() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); let db = env.open_db(None).unwrap(); @@ -340,7 +339,7 @@ mod test { #[test] fn test_get_dup() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); let db = env.create_db(None, DUP_SORT).unwrap(); @@ -386,7 +385,7 @@ mod test { #[test] fn test_get_dupfixed() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); let db = env.create_db(None, DUP_SORT | DUP_FIXED).unwrap(); @@ -408,7 +407,7 @@ mod test { #[test] fn test_iter() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); let db = env.open_db(None).unwrap(); @@ -440,7 +439,7 @@ mod test { #[test] fn test_iter_dup() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); let db = env.create_db(None, DUP_SORT).unwrap(); @@ -487,7 +486,7 @@ mod test { #[test] fn test_put_del() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); let db = env.open_db(None).unwrap(); diff --git a/src/environment.rs b/src/environment.rs index 14fb468..b298175 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -179,7 +179,7 @@ impl EnvironmentBuilder { ffi::mdb_env_close(env)) } lmdb_try_with_cleanup!(ffi::mdb_env_open(env, - CString::from_slice(path.as_os_str().as_byte_slice()).as_ptr(), + CString::from_slice(path.as_os_str().as_bytes()).as_ptr(), self.flags.bits(), mode.bits() as mode_t), ffi::mdb_env_close(env)); @@ -241,11 +241,13 @@ mod test { use std::old_io as io; use flags::*; + use tempdir; + use super::*; #[test] fn test_open() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); // opening non-existent env with read-only should fail assert!(Environment::new().set_flags(READ_ONLY) @@ -263,7 +265,7 @@ mod test { #[test] fn test_begin_txn() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); { // writable environment let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); @@ -284,7 +286,7 @@ mod test { #[test] fn test_open_db() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); let env = Environment::new().set_max_dbs(1) .open(dir.path(), io::USER_RWX) .unwrap(); @@ -295,7 +297,7 @@ mod test { #[test] fn test_create_db() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); let env = Environment::new().set_max_dbs(11) .open(dir.path(), io::USER_RWX) .unwrap(); @@ -306,7 +308,7 @@ mod test { #[test] fn test_close_database() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); let mut env = Environment::new().set_max_dbs(10) .open(dir.path(), io::USER_RWX) .unwrap(); @@ -318,7 +320,7 @@ mod test { #[test] fn test_sync() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); { let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); assert!(env.sync(true).is_ok()); @@ -326,7 +328,7 @@ mod test { let env = Environment::new().set_flags(READ_ONLY) .open(dir.path(), io::USER_RWX) .unwrap(); - env.sync(true).unwrap(); + assert!(env.sync(true).is_err()); } } } diff --git a/src/lib.rs b/src/lib.rs index 051b0e9..22e81f5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,16 +4,16 @@ //! Provides the minimal amount of abstraction necessary to interact with LMDB safely in Rust. In //! general, the API is very similar to the LMDB [C-API](http://symas.com/mdb/doc/). -#![feature(collections, core, hash, io, libc, optin_builtin_traits, std_misc, test, unsafe_destructor)] -#![cfg_attr(test, feature(rand))] +#![feature(core, libc, old_io, optin_builtin_traits, path, std_misc, unsafe_destructor)] +#![cfg_attr(test, feature(test))] extern crate libc; extern crate "lmdb-sys" as ffi; -extern crate test; -extern crate collections; -#[macro_use] -extern crate bitflags; +#[cfg(test)] extern crate rand; +#[cfg(test)] extern crate tempdir; +#[cfg(test)] extern crate test; +#[macro_use] extern crate bitflags; pub use cursor::{ Cursor, @@ -66,6 +66,8 @@ mod test_utils { use std::old_io as io; + use tempdir; + use super::*; pub fn get_key(n: u32) -> String { @@ -76,8 +78,8 @@ mod test_utils { format!("data{}", n) } - pub fn setup_bench_db<'a>(num_rows: u32) -> (io::TempDir, Environment) { - let dir = io::TempDir::new("test").unwrap(); + pub fn setup_bench_db<'a>(num_rows: u32) -> (tempdir::TempDir, Environment) { + let dir = tempdir::TempDir::new("test").unwrap(); let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); { diff --git a/src/transaction.rs b/src/transaction.rs index e4b9cfb..976fb96 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -1,6 +1,6 @@ use libc::{c_uint, c_void, size_t}; use std::{mem, ptr, raw}; -use std::marker; +use std::marker::{PhantomData, PhantomFn} ; use std::old_io::BufWriter; use ffi; @@ -14,7 +14,7 @@ use flags::{DatabaseFlags, EnvironmentFlags, WriteFlags}; /// An LMDB transaction. /// /// All database operations require a transaction. -pub trait Transaction<'env> { +pub trait Transaction<'env> : PhantomFn<(), &'env Environment> { /// Returns a raw pointer to the underlying LMDB transaction. /// @@ -108,7 +108,7 @@ impl<'env, T> TransactionExt<'env> for T where T: Transaction<'env> {} /// An LMDB read-only transaction. pub struct RoTransaction<'env> { txn: *mut ffi::MDB_txn, - _marker: marker::ContravariantLifetime<'env>, + _marker: PhantomData<&'env ()>, } impl <'env> !Sync for RoTransaction<'env> {} @@ -133,7 +133,7 @@ impl <'env> RoTransaction<'env> { ptr::null_mut(), ffi::MDB_RDONLY, &mut txn))); - Ok(RoTransaction { txn: txn, _marker: marker::ContravariantLifetime::<'env> }) + Ok(RoTransaction { txn: txn, _marker: PhantomData }) } } @@ -153,7 +153,7 @@ impl <'env> RoTransaction<'env> { mem::forget(self); ffi::mdb_txn_reset(txn) }; - InactiveTransaction { txn: txn, _marker: marker::ContravariantLifetime::<'env> } + InactiveTransaction { txn: txn, _marker: PhantomData } } } @@ -166,7 +166,7 @@ impl <'env> Transaction<'env> for RoTransaction<'env> { /// An inactive read-only transaction. pub struct InactiveTransaction<'env> { txn: *mut ffi::MDB_txn, - _marker: marker::ContravariantLifetime<'env>, + _marker: PhantomData<&'env ()>, } #[unsafe_destructor] @@ -188,14 +188,14 @@ impl <'env> InactiveTransaction<'env> { mem::forget(self); try!(lmdb_result(ffi::mdb_txn_renew(txn))) }; - Ok(RoTransaction { txn: txn, _marker: marker::ContravariantLifetime::<'env> }) + Ok(RoTransaction { txn: txn, _marker: PhantomData }) } } /// An LMDB read-write transaction. pub struct RwTransaction<'env> { txn: *mut ffi::MDB_txn, - _marker: marker::ContravariantLifetime<'env>, + _marker: PhantomData<&'env ()>, } impl <'env> !Sync for RwTransaction<'env> {} @@ -220,7 +220,7 @@ impl <'env> RwTransaction<'env> { ptr::null_mut(), EnvironmentFlags::empty().bits(), &mut txn))); - Ok(RwTransaction { txn: txn, _marker: marker::ContravariantLifetime::<'env> }) + Ok(RwTransaction { txn: txn, _marker: PhantomData }) } } @@ -352,7 +352,7 @@ impl <'env> RwTransaction<'env> { let env: *mut ffi::MDB_env = ffi::mdb_txn_env(self.txn()); ffi::mdb_txn_begin(env, self.txn(), 0, &mut nested); } - Ok(RwTransaction { txn: nested, _marker: marker::ContravariantLifetime::<'env> }) + Ok(RwTransaction { txn: nested, _marker: PhantomData }) } } @@ -367,7 +367,7 @@ mod test { use std::old_io as io; use std::ptr; - use std::rand::{Rng, XorShiftRng}; + use rand::{Rng, XorShiftRng}; use std::sync::{Arc, Barrier, Future}; use test::{Bencher, black_box}; @@ -377,11 +377,12 @@ mod test { use error::*; use flags::*; use super::*; + use tempdir; use test_utils::*; #[test] fn test_put_get_del() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); let db = env.open_db(None).unwrap(); @@ -403,7 +404,7 @@ mod test { #[test] fn test_reserve() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); let db = env.open_db(None).unwrap(); @@ -424,7 +425,7 @@ mod test { #[test] fn test_inactive_txn() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); let db = env.open_db(None).unwrap(); @@ -442,7 +443,7 @@ mod test { #[test] fn test_nested_txn() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); let db = env.open_db(None).unwrap(); @@ -462,7 +463,7 @@ mod test { #[test] fn test_clear_db() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); let env = Environment::new().open(dir.path(), io::USER_RWX).unwrap(); let db = env.open_db(None).unwrap(); @@ -485,7 +486,7 @@ mod test { #[test] fn test_drop_db() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); let env = Environment::new().set_max_dbs(2) .open(dir.path(), io::USER_RWX).unwrap(); let db = env.create_db(Some("test"), DatabaseFlags::empty()).unwrap(); @@ -506,10 +507,10 @@ mod test { #[test] fn test_concurrent_readers_single_writer() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); let env: Arc = Arc::new(Environment::new().open(dir.path(), io::USER_RWX).unwrap()); - let n = 10us; // Number of concurrent readers + let n = 10usize; // Number of concurrent readers let barrier = Arc::new(Barrier::new(n + 1)); let mut futures: Vec> = Vec::with_capacity(n); @@ -548,10 +549,10 @@ mod test { #[test] fn test_concurrent_writers() { - let dir = io::TempDir::new("test").unwrap(); + let dir = tempdir::TempDir::new("test").unwrap(); let env = Arc::new(Environment::new().open(dir.path(), io::USER_RWX).unwrap()); - let n = 10us; // Number of concurrent writers + let n = 10usize; // Number of concurrent writers let mut futures: Vec> = Vec::with_capacity(n); let key = "key"; @@ -595,7 +596,7 @@ mod test { XorShiftRng::new_unseeded().shuffle(keys.as_mut_slice()); b.iter(|| { - let mut i = 0us; + let mut i = 0usize; for key in keys.iter() { i = i + txn.get(db, key.as_bytes()).unwrap().len(); }