diff --git a/Cargo.toml b/Cargo.toml index 285bd6e..0e1179a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,3 +11,6 @@ description = "The package provides an interface to SQLite." [dependencies] libc = "*" sqlite3-sys = "*" + +[dev-dependencies] +temporary = "*" diff --git a/src/lib.rs b/src/lib.rs index 16778a9..77ac048 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,53 @@ +#![allow(unused_unsafe)] + extern crate libc; extern crate sqlite3_sys as raw; +use std::path::Path; + +/// A result. +pub type Result = std::result::Result; + +/// An error. +#[derive(Debug)] +pub struct Error { + pub code: ErrorCode, + pub message: Option, +} + +macro_rules! raise( + ($message:expr) => ( + return Err(::Error { code: ::ErrorCode::Error, message: Some($message.to_string()) }) + ); + ($code:expr, $message:expr) => ( + return Err(::Error { code: $code, message: $message }) + ); +); + +macro_rules! success( + ($result:expr) => ( + match $result { + ::raw::SQLITE_OK => {}, + code => raise!(unsafe { ::std::mem::transmute(code as i8) }, None), + } + ); +); + +macro_rules! path_to_c_str( + ($path:expr) => ({ + match $path.to_str() { + Some(path) => match ::std::ffi::CString::new(path) { + Ok(string) => string.as_ptr(), + Err(_) => raise!("failed to process a path"), + }, + None => raise!("failed to process a path"), + } + }); +); + /// A result code. #[derive(Clone, Copy, Debug)] -pub enum ResultCode { +pub enum ErrorCode { Abort = raw::SQLITE_ABORT as isize, Authorization = raw::SQLITE_AUTH as isize, Busy = raw::SQLITE_BUSY as isize, @@ -37,6 +81,27 @@ pub enum ResultCode { Warning = raw::SQLITE_WARNING as isize, } -#[cfg(test)] -mod tests { +/// A database. +pub struct Database { + db: *mut raw::sqlite3, +} + +impl Database { + pub fn open(path: &Path) -> Result { + let mut db = 0 as *mut _; + unsafe { success!(raw::sqlite3_open(path_to_c_str!(path), &mut db)) }; + Ok(Database { db: db }) + } +} + +impl Drop for Database { + #[inline] + fn drop(&mut self) { + unsafe { ::raw::sqlite3_close(self.db) }; + } +} + +#[inline] +pub fn open(path: &Path) -> Result { + Database::open(path) } diff --git a/tests/lib.rs b/tests/lib.rs new file mode 100644 index 0000000..15f9014 --- /dev/null +++ b/tests/lib.rs @@ -0,0 +1,20 @@ +extern crate sqlite; +extern crate temporary; + +use std::path::PathBuf; +use temporary::Directory; + +macro_rules! ok( + ($result:expr) => ($result.unwrap()); +); + +#[test] +fn open() { + let (path, _directory) = setup(); + let _database = ok!(sqlite::open(&path)); +} + +fn setup() -> (PathBuf, Directory) { + let directory = ok!(Directory::new("sqlite")); + (directory.path().join("database.sqlite3"), directory) +}