Clean up the busy callback

This commit is contained in:
Ivan Ukhov 2015-06-08 14:52:13 -04:00
parent fd9cf2b2d2
commit a5c0234aa1
2 changed files with 26 additions and 21 deletions

View File

@ -6,19 +6,24 @@ use std::path::Path;
use {Result, Statement}; use {Result, Statement};
/// A database. /// A database.
pub struct Database { pub struct Database<'l> {
raw: *mut raw::sqlite3, raw: *mut raw::sqlite3,
busy_callback: Option<Box<FnMut(usize) -> bool + 'l>>,
phantom: PhantomData<raw::sqlite3>, phantom: PhantomData<raw::sqlite3>,
} }
impl Database { impl<'l> Database<'l> {
/// Establish a database connect. /// Establish a database connect.
pub fn open(path: &Path) -> Result<Database> { pub fn open(path: &Path) -> Result<Database<'l>> {
let mut raw = 0 as *mut _; let mut raw = 0 as *mut _;
unsafe { unsafe {
success!(raw::sqlite3_open(path_to_c_str!(path), &mut raw)); success!(raw::sqlite3_open(path_to_c_str!(path), &mut raw));
} }
Ok(Database { raw: raw, phantom: PhantomData }) Ok(Database {
raw: raw,
busy_callback: None,
phantom: PhantomData,
})
} }
/// Execute a query without processing the resulting rows if any. /// Execute a query without processing the resulting rows if any.
@ -39,12 +44,11 @@ impl Database {
pub fn iterate<F>(&self, sql: &str, callback: F) -> Result<()> pub fn iterate<F>(&self, sql: &str, callback: F) -> Result<()>
where F: FnMut(Vec<(String, String)>) -> bool where F: FnMut(Vec<(String, String)>) -> bool
{ {
use std::ops::Deref;
let callback = Box::new(callback);
unsafe { unsafe {
let callback = Box::new(callback);
success!(self, raw::sqlite3_exec(self.raw, str_to_c_str!(sql), success!(self, raw::sqlite3_exec(self.raw, str_to_c_str!(sql),
Some(execute_callback::<F>), Some(execute_callback::<F>),
callback.deref() as *const _ as *mut _ as *mut _, &*callback as *const _ as *mut _ as *mut _,
0 as *mut _)); 0 as *mut _));
} }
Ok(()) Ok(())
@ -52,7 +56,7 @@ impl Database {
/// Create a prepared statement. /// Create a prepared statement.
#[inline] #[inline]
pub fn prepare<'l>(&'l self, sql: &str) -> Result<Statement<'l>> { pub fn prepare(&'l self, sql: &str) -> Result<Statement<'l>> {
::statement::new(self, sql) ::statement::new(self, sql)
} }
@ -63,13 +67,15 @@ impl Database {
/// the operation will be repeated. /// the operation will be repeated.
#[inline] #[inline]
pub fn set_busy_handler<F>(&mut self, callback: F) -> Result<()> pub fn set_busy_handler<F>(&mut self, callback: F) -> Result<()>
where F: FnMut(usize) -> bool where F: FnMut(usize) -> bool + 'l
{ {
use std::mem::transmute; try!(self.remove_busy_handler());
let callback = Box::new(callback);
unsafe { unsafe {
success!(raw::sqlite3_busy_handler(self.raw, Some(busy_callback::<F>), let callback = Box::new(callback);
transmute::<_, *mut c_void>(callback))); let result = raw::sqlite3_busy_handler(self.raw, Some(busy_callback::<F>),
&*callback as *const _ as *mut _ as *mut _);
self.busy_callback = Some(callback);
success!(result);
} }
Ok(()) Ok(())
} }
@ -85,16 +91,17 @@ impl Database {
/// Remove the callback handling busy events. /// Remove the callback handling busy events.
#[inline] #[inline]
pub fn remove_busy_handler(&mut self) -> Result<()> { pub fn remove_busy_handler(&mut self) -> Result<()> {
unsafe { ::std::mem::replace(&mut self.busy_callback, None);
success!(raw::sqlite3_busy_handler(self.raw, None, 0 as *mut _)); unsafe { success!(raw::sqlite3_busy_handler(self.raw, None, 0 as *mut _)) };
}
Ok(()) Ok(())
} }
} }
impl Drop for Database { impl<'l> Drop for Database<'l> {
#[inline] #[inline]
#[allow(unused_must_use)]
fn drop(&mut self) { fn drop(&mut self) {
self.remove_busy_handler();
unsafe { raw::sqlite3_close(self.raw) }; unsafe { raw::sqlite3_close(self.raw) };
} }
} }
@ -107,9 +114,7 @@ pub fn as_raw(database: &Database) -> *mut raw::sqlite3 {
extern fn busy_callback<F>(callback: *mut c_void, attempts: c_int) -> c_int extern fn busy_callback<F>(callback: *mut c_void, attempts: c_int) -> c_int
where F: FnMut(usize) -> bool where F: FnMut(usize) -> bool
{ {
unsafe { unsafe { if (*(callback as *mut F))(attempts as usize) { 1 } else { 0 } }
if (*(callback as *mut F))(attempts as usize) { 1 } else { 0 }
}
} }
extern fn execute_callback<F>(callback: *mut c_void, count: c_int, values: *mut *mut c_char, extern fn execute_callback<F>(callback: *mut c_void, count: c_int, values: *mut *mut c_char,

View File

@ -68,7 +68,7 @@ pub use statement::{Statement, Binding, Value};
/// Open a database. /// Open a database.
#[inline] #[inline]
pub fn open(path: &std::path::Path) -> Result<Database> { pub fn open<'l>(path: &std::path::Path) -> Result<Database<'l>> {
Database::open(path) Database::open(path)
} }