56 lines
1.6 KiB
Rust
56 lines
1.6 KiB
Rust
use tokio::sync::{mpsc, oneshot};
|
|
|
|
struct DbThreadInner {
|
|
op_sender: mpsc::Sender<Box<dyn FnOnce(&mut diesel::SqliteConnection) + Send>>,
|
|
join_handle: std::thread::JoinHandle<()>,
|
|
}
|
|
|
|
pub struct DbThread(Option<DbThreadInner>);
|
|
|
|
impl DbThread {
|
|
pub fn new(mut connection: diesel::SqliteConnection, buffer: usize) -> Self {
|
|
let (op_sender, mut op_receiver) =
|
|
mpsc::channel::<Box<dyn FnOnce(&mut diesel::SqliteConnection) + Send>>(buffer);
|
|
let join_handle = std::thread::spawn(move || loop {
|
|
let Some(f) = op_receiver.blocking_recv() else {
|
|
break;
|
|
};
|
|
f(&mut connection);
|
|
});
|
|
Self(Some(DbThreadInner {
|
|
op_sender,
|
|
join_handle,
|
|
}))
|
|
}
|
|
pub async fn run_on<
|
|
F: FnOnce(&mut diesel::SqliteConnection) -> T + Send + 'static,
|
|
T: Send + 'static,
|
|
>(
|
|
&self,
|
|
f: F,
|
|
) -> T {
|
|
let (result_sender, result_receiver) = oneshot::channel();
|
|
self.0
|
|
.as_ref()
|
|
.unwrap()
|
|
.op_sender
|
|
.send(Box::new(move |connection| {
|
|
// if send failed, the future must have been canceled, so ignore send failures
|
|
let _ = result_sender.send(f(connection));
|
|
}))
|
|
.await
|
|
.expect("send to succeed");
|
|
result_receiver.await.expect("result to be written")
|
|
}
|
|
}
|
|
|
|
impl Drop for DbThread {
|
|
fn drop(&mut self) {
|
|
let DbThreadInner {
|
|
op_sender,
|
|
join_handle,
|
|
} = self.0.take().unwrap();
|
|
drop(op_sender);
|
|
join_handle.join().unwrap();
|
|
}
|
|
}
|