engine/map/src/async_db.rs
2024-08-23 13:22:09 +02:00

89 lines
2.2 KiB
Rust

// engine
use engine::prelude::*;
// std
use std::mem;
use std::sync::{Arc, Mutex, RwLock};
use super::map_db::MapDataBase;
// sql
use anyhow::Result;
pub struct AsyncDBAccess {
sql: Arc<Mutex<MapDataBase>>,
async_thread: RwLock<AsyncThread<Result<()>>>,
queue: RwLock<Vec<DispatchCommand>>,
}
impl AsyncDBAccess {
pub fn new(map_db: MapDataBase) -> AsyncDBAccess {
AsyncDBAccess {
sql: Arc::new(Mutex::new(map_db)),
async_thread: RwLock::new(AsyncThread::spawn(move || Ok(()))),
queue: RwLock::new(Vec::new()),
}
}
pub fn add<F>(&self, f: F) -> Result<()>
where
F: FnOnce(&MapDataBase) -> Result<()> + Send + Sync + 'static,
{
let sql_clone = self.sql.clone();
self.queue
.write()
.unwrap()
.push(DispatchCommand::new(sql_clone, f));
Ok(())
}
pub fn dispatch(&self) -> Result<()> {
let mut async_thread = self.async_thread.write().unwrap();
let mut queue = self.queue.write().unwrap();
// check if async thread is returned
if async_thread.check()? {
// check if there are calls to be dispatched
if !queue.is_empty() {
// move calls into queue to call it in a thread
let mut dispatch_queue = Vec::new();
mem::swap(&mut dispatch_queue, &mut queue);
*async_thread = AsyncThread::spawn(move || {
for dispatch_call in dispatch_queue {
dispatch_call.call()?;
}
Ok(())
});
}
}
Ok(())
}
}
unsafe impl Sync for AsyncDBAccess {}
struct DispatchCommand {
sql: Arc<Mutex<MapDataBase>>,
command: Box<dyn FnOnce(&MapDataBase) -> Result<()> + Send + Sync>,
}
impl DispatchCommand {
pub fn new<F>(sql: Arc<Mutex<MapDataBase>>, command: F) -> Self
where
F: FnOnce(&MapDataBase) -> Result<()> + Send + Sync + 'static,
{
DispatchCommand {
sql,
command: Box::new(command),
}
}
pub fn call(self) -> Result<()> {
let sql_lock = self.sql.lock().unwrap();
(self.command)(&*sql_lock)
}
}