diff --git a/.travis.yml b/.travis.yml index 7c030f6..dc53c92 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: rust rust: + - 1.38.0 - 1.20.0 - - 1.15.0 - nightly matrix: allow_failures: diff --git a/src/database/batch.rs b/src/database/batch.rs index 8064bf3..7a7fe4f 100644 --- a/src/database/batch.rs +++ b/src/database/batch.rs @@ -52,7 +52,7 @@ impl Batch for Database { if error == ptr::null_mut() { Ok(()) } else { - Err(Error::new_from_i8(error)) + Err(Error::new_from_char(error)) } } } @@ -124,9 +124,9 @@ pub trait WritebatchIterator { } extern "C" fn put_callback>(state: *mut c_void, - key: *const i8, + key: *const c_char, keylen: size_t, - val: *const i8, + val: *const c_char, vallen: size_t) { unsafe { let iter: &mut T = &mut *(state as *mut T); @@ -138,7 +138,7 @@ extern "C" fn put_callback>(state: *mut c_v } extern "C" fn deleted_callback>(state: *mut c_void, - key: *const i8, + key: *const c_char, keylen: size_t) { unsafe { let iter: &mut T = &mut *(state as *mut T); diff --git a/src/database/comparator.rs b/src/database/comparator.rs index f0ddd57..64e278d 100644 --- a/src/database/comparator.rs +++ b/src/database/comparator.rs @@ -59,9 +59,9 @@ unsafe trait InternalComparator : Comparator where Self: Sized { } extern "C" fn compare(state: *mut c_void, - a: *const i8, + a: *const c_char, a_len: size_t, - b: *const i8, + b: *const c_char, b_len: size_t) -> i32 { unsafe { diff --git a/src/database/error.rs b/src/database/error.rs index 914f6f2..cd9e097 100644 --- a/src/database/error.rs +++ b/src/database/error.rs @@ -1,6 +1,6 @@ //! The module defining custom leveldb error type. -use libc::c_void; +use libc::{c_char, c_void}; use leveldb_sys::leveldb_free; use std; @@ -21,13 +21,18 @@ impl Error { /// /// This method is `unsafe` because the pointer must be valid and point to heap. /// The pointer will be passed to `free`! - pub unsafe fn new_from_i8(message: *const i8) -> Error { + pub(crate) unsafe fn new_from_char(message: *const c_char) -> Error { use std::str::from_utf8; use std::ffi::CStr; - let err_string = from_utf8(CStr::from_ptr(message).to_bytes()).unwrap().to_string(); + let err_string = from_utf8(CStr::from_ptr(message).to_bytes()) + .map(|s| s.to_string()); leveldb_free(message as *mut c_void); - Error::new(err_string) + + match err_string { + Ok(err_string) => Error::new(err_string), + Err(_) => Error::new("The error returned by LevelDB is not valid UTF-8".into()) + } } } diff --git a/src/database/kv.rs b/src/database/kv.rs index 66a9543..250a51d 100644 --- a/src/database/kv.rs +++ b/src/database/kv.rs @@ -70,7 +70,7 @@ impl KV for Database { if error == ptr::null_mut() { Ok(()) } else { - Err(Error::new_from_i8(error)) + Err(Error::new_from_char(error)) } }) } @@ -96,7 +96,7 @@ impl KV for Database { if error == ptr::null_mut() { Ok(()) } else { - Err(Error::new_from_i8(error)) + Err(Error::new_from_char(error)) } }) } @@ -119,7 +119,7 @@ impl KV for Database { if error == ptr::null_mut() { Ok(Bytes::from_raw(result as *mut u8, length)) } else { - Err(Error::new_from_i8(error)) + Err(Error::new_from_char(error)) } }) } diff --git a/src/database/management.rs b/src/database/management.rs index 0e115bf..b29d58d 100644 --- a/src/database/management.rs +++ b/src/database/management.rs @@ -4,6 +4,7 @@ use error::Error; use std::ffi::CString; use std::ptr; use std::path::Path; +use libc::c_char; use leveldb_sys::{leveldb_destroy_db, leveldb_repair_db}; @@ -14,13 +15,13 @@ pub fn destroy(name: &Path, options: Options) -> Result<(), Error> { let c_string = CString::new(name.to_str().unwrap()).unwrap(); let c_options = c_options(&options, None); leveldb_destroy_db(c_options, - c_string.as_bytes_with_nul().as_ptr() as *const i8, + c_string.as_bytes_with_nul().as_ptr() as *const c_char, &mut error); if error == ptr::null_mut() { Ok(()) } else { - Err(Error::new_from_i8(error)) + Err(Error::new_from_char(error)) } } } @@ -32,13 +33,13 @@ pub fn repair(name: &Path, options: Options) -> Result<(), Error> { let c_string = CString::new(name.to_str().unwrap()).unwrap(); let c_options = c_options(&options, None); leveldb_repair_db(c_options, - c_string.as_bytes_with_nul().as_ptr() as *const i8, + c_string.as_bytes_with_nul().as_ptr() as *const c_char, &mut error); if error == ptr::null_mut() { Ok(()) } else { - Err(Error::new_from_i8(error)) + Err(Error::new_from_char(error)) } } } diff --git a/src/database/mod.rs b/src/database/mod.rs index 5dc9a09..f759884 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -7,6 +7,9 @@ use leveldb_sys::*; use self::options::{Options, c_options}; use self::error::Error; use std::ffi::CString; +use libc::c_char; +#[cfg(unix)] +use std::os::unix::ffi::OsStrExt; use std::path::Path; @@ -107,17 +110,24 @@ impl Database { pub fn open(name: &Path, options: Options) -> Result, Error> { let mut error = ptr::null_mut(); unsafe { - let c_string = CString::new(name.to_str().unwrap()).unwrap(); + #[cfg(unix)] + let c_string = CString::new(name.as_os_str().as_bytes()).unwrap(); + #[cfg(not(unix))] + let c_string = CString::new( + name.to_str() + .ok_or_else(|| Error::new("Path is not valid Unicode".into()))?, + ) + .unwrap(); let c_options = c_options(&options, None); let db = leveldb_open(c_options as *const leveldb_options_t, - c_string.as_bytes_with_nul().as_ptr() as *const i8, + c_string.as_bytes_with_nul().as_ptr() as *const c_char, &mut error); leveldb_options_destroy(c_options); if error == ptr::null_mut() { Ok(Database::new(db, options, None)) } else { - Err(Error::new_from_i8(error)) + Err(Error::new_from_char(error)) } } } @@ -140,14 +150,14 @@ impl Database { let c_string = CString::new(name.to_str().unwrap()).unwrap(); let c_options = c_options(&options, Some(comp_ptr)); let db = leveldb_open(c_options as *const leveldb_options_t, - c_string.as_bytes_with_nul().as_ptr() as *const i8, + c_string.as_bytes_with_nul().as_ptr() as *const c_char, &mut error); leveldb_options_destroy(c_options); if error == ptr::null_mut() { Ok(Database::new(db, options, Some(comp_ptr))) } else { - Err(Error::new_from_i8(error)) + Err(Error::new_from_char(error)) } } }