Refine set_busy_handler

This commit is contained in:
Ivan Ukhov 2015-06-08 11:28:43 -04:00
parent 159b22c159
commit 81dcb73b8f
2 changed files with 24 additions and 20 deletions

View File

@ -11,10 +11,6 @@ pub struct Database {
phantom: PhantomData<raw::sqlite3>, phantom: PhantomData<raw::sqlite3>,
} }
/// A callback triggered when the database is busy and rejects an operation. If
/// the callback returns `true`, the operation will be repeated.
pub type BusyCallback<'l> = FnMut(usize) -> bool + 'l;
/// A callback triggered for each row of an executed SQL query. If the callback /// A callback triggered for each row of an executed SQL query. If the callback
/// returns `false`, no more rows will be processed. /// returns `false`, no more rows will be processed.
pub type ExecuteCallback<'l> = FnMut(Vec<(String, String)>) -> bool + 'l; pub type ExecuteCallback<'l> = FnMut(Vec<(String, String)>) -> bool + 'l;
@ -36,10 +32,10 @@ impl Database {
match callback { match callback {
Some(callback) => unsafe { Some(callback) => unsafe {
let mut callback = Box::new(callback); let mut 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), Some(execute_callback),
&mut callback as *mut _ as *mut _, &mut callback as *mut _ as *mut _,
0 as *mut _)); 0 as *mut _));
}, },
None => unsafe { None => unsafe {
success!(self, raw::sqlite3_exec(self.raw, str_to_c_str!(sql), None, success!(self, raw::sqlite3_exec(self.raw, str_to_c_str!(sql), None,
@ -56,15 +52,22 @@ impl Database {
} }
/// Set a callback to handle rejected operations when the database is busy. /// Set a callback to handle rejected operations when the database is busy.
pub fn set_busy_handler(&mut self, callback: Option<&mut BusyCallback>) -> Result<()> { ///
/// The callback is triggered when the database cannot perform an operation
/// due to processing of a request from another client. If the callback
/// returns `true`, the operation will be repeated.
pub fn set_busy_handler<F: FnMut(usize) -> bool>(&mut self, callback: Option<F>)
-> Result<()> {
match callback { match callback {
Some(callback) => unsafe { Some(callback) => unsafe {
let mut callback = Box::new(callback); use std::mem::transmute;
success!(self, raw::sqlite3_busy_handler(self.raw, Some(busy_callback), let callback = Box::new(callback);
&mut callback as *mut _ as *mut _)); success!(raw::sqlite3_busy_handler(self.raw, Some(busy_callback::<F>),
transmute::<_, *mut c_void>(callback)));
}, },
None => unsafe { None => unsafe {
success!(self, raw::sqlite3_busy_handler(self.raw, None, 0 as *mut _)); success!(raw::sqlite3_busy_handler(self.raw, None, 0 as *mut _));
}, },
} }
Ok(()) Ok(())
@ -90,11 +93,8 @@ pub fn as_raw(database: &Database) -> *mut raw::sqlite3 {
database.raw database.raw
} }
extern fn busy_callback(callback: *mut c_void, attempts: c_int) -> c_int { extern fn busy_callback<F: FnMut(usize) -> bool>(callback: *mut c_void, attempts: c_int) -> c_int {
unsafe { if unsafe { (*(callback as *mut F))(attempts as usize) } { 1 } else { 0 }
let ref mut callback = *(callback as *mut Box<&mut BusyCallback>);
if callback(attempts as usize) { 1 } else { 0 }
}
} }
extern fn execute_callback(callback: *mut c_void, count: c_int, values: *mut *mut c_char, extern fn execute_callback(callback: *mut c_void, count: c_int, values: *mut *mut c_char,
@ -137,6 +137,10 @@ mod tests {
fn set_busy_handler() { fn set_busy_handler() {
let (path, _directory) = setup(); let (path, _directory) = setup();
let mut database = ok!(Database::open(&path)); let mut database = ok!(Database::open(&path));
ok!(database.set_busy_handler(Some(&mut |_| true))); do_set_busy_handler(&mut database);
}
fn do_set_busy_handler(database: &mut Database) {
ok!(database.set_busy_handler(Some(|_| true)));
} }
} }

View File

@ -62,7 +62,7 @@ mod result;
mod statement; mod statement;
pub use error::Error; pub use error::Error;
pub use database::{BusyCallback, Database, ExecuteCallback}; pub use database::{Database, ExecuteCallback};
pub use result::{Result, ResultCode}; pub use result::{Result, ResultCode};
pub use statement::{Statement, Binding, Value}; pub use statement::{Statement, Binding, Value};