use std::{ borrow::Borrow, collections::VecDeque, marker::PhantomData, path::Path, sync::{Arc, RwLock, atomic::AtomicBool}, }; use futures::task::AtomicWaker; use redb::{Error, Key, ReadableDatabase, TableDefinition, Value}; use serde::{Serialize, de::DeserializeOwned}; const USERS: TableDefinition> = TableDefinition::new("users"); const SERVERS: TableDefinition> = TableDefinition::new("servers"); const SETTINGS: TableDefinition> = TableDefinition::new("settings"); #[derive(Debug)] pub struct TableInner { db: Arc, } impl Clone for TableInner { fn clone(&self) -> Self { Self { db: Arc::clone(&self.db), } } } impl TableInner { fn new(db: Arc) -> Self { Self { db } } } impl TableInner { async fn get<'a, K: Key, V: Serialize + DeserializeOwned>( &self, table: TableDefinition<'static, K, Vec>, key: impl Borrow>, ) -> Result> { let db: &redb::Database = &self.db.as_ref().database; let db_reader = db.begin_read()?; let table = db_reader.open_table(table)?; table .get(key)? .map(|value| bson::deserialize_from_slice(&value.value())) .transpose() .map_err(|e| redb::Error::Io(std::io::Error::other(e))) } async fn insert< 'a, 'b, K: Key + Send + Sync, V: Serialize + DeserializeOwned + Send + Sync + 'a, >( &'b self, table: TableDefinition<'static, K, Vec>, key: impl Borrow> + Send + 'b, value: V, ) -> Result> { let db: &redb::Database = &self.db.as_ref().database; // self.db // .writing // .store(true, std::sync::atomic::Ordering::SeqCst); // let out = tokio::task::spawn_blocking(move || -> Result> let out = tokio::task::spawn_blocking(|| -> Result> { let db_writer = db.begin_write()?; let out = { let mut table = db_writer.open_table(table)?; let serialized_value = bson::serialize_to_vec(&value) .map_err(|e| redb::Error::Io(std::io::Error::other(e)))?; let previous = table.insert(key, &serialized_value)?; let out = previous .map(|value| bson::deserialize_from_slice(&value.value())) .transpose() .map_err(|e| redb::Error::Io(std::io::Error::other(e))); out }; db_writer.commit()?; out }) .await .expect("Task panicked"); out } } // impl Table for TableInner { // async fn get(&self, key: K) -> Result> {} // async fn insert(&self, key: K, value: V) -> Result> {} // async fn modify(&self, key: K, v: FnOnce(V) -> V) -> Result {} // async fn remove(&self, key: K) -> Result> {} // } #[derive(Debug)] pub struct Users(TableInner); impl Clone for Users { fn clone(&self) -> Self { Self(self.0.clone()) } } impl Users { const TABLE: TableDefinition<'static, uuid::Uuid, Vec> = USERS; } #[derive(Debug)] pub struct Servers(TableInner); impl Clone for Servers { fn clone(&self) -> Self { Self(self.0.clone()) } } impl Servers { const TABLE: TableDefinition<'static, uuid::Uuid, Vec> = SERVERS; } #[derive(Debug)] pub struct Settings(TableInner); impl Clone for Settings { fn clone(&self) -> Self { Self(self.0.clone()) } } impl Settings { const TABLE: TableDefinition<'static, uuid::Uuid, Vec> = SETTINGS; } #[derive(Debug, Clone)] pub struct Database { users: Users, servers: Servers, settings: Settings, handle: Arc, } #[derive(Debug)] pub struct DatabaseHandle { database: redb::Database, writing: AtomicBool, wakers: RwLock>, } #[derive(Debug)] pub struct DatabaseWriterGuard<'a> { handle: &'a DatabaseHandle, dropper: Arc, } // impl Drop for DatabaseWriterGuard<'_> { // fn drop(&mut self) { // self.handle // .writing // .store(false, std::sync::atomic::Ordering::SeqCst); // let is_panicking = std::thread::panicking(); // let Ok(writer) = self.handle.wakers.write() else { // if is_panicking { // return; // } else { // panic!("Wakers lock poisoned"); // } // } // if let Some(waker) = (self.handle.wakers.write()).pop() { // waker.wake(); // }; // // let mut wakers = self.handle.wakers.write().expect(); // // if let Some(waker) = self.handle.wakers.write().expect("Wakers lock poisoned").pop_front() { // // waker.wake(); // // } // // while let Some(waker) = wakers.pop_front() { // // waker.wake(); // // } // } // } type Result = core::result::Result; pub trait Table { fn insert( &self, key: K, value: V, ) -> impl Future>> + Send; fn modify( &self, key: K, v: impl FnOnce(V) -> O, ) -> impl Future> + Send; fn remove( &self, key: K, ) -> impl Future>> + Send; fn get( &self, key: K, ) -> impl Future>> + Send; } impl Database { pub fn create(path: impl AsRef) -> Result { let writing = AtomicBool::new(false); let wakers = RwLock::new(VecDeque::new()); let db = redb::Database::create(path)?; let db = Arc::new(DatabaseHandle { database: db, writing, wakers, }); let table_inner = TableInner::new(Arc::clone(&db)); let users = Users(table_inner.clone()); let servers = Servers(table_inner.clone()); let settings = Settings(table_inner.clone()); Ok(Self { servers, users, settings, handle: db, }) } }