use rustbreak::{deser::Yaml as Ron, FileDatabase}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serenity::{framework::standard::CommandError as Error, model::id::GuildId, prelude::*}; use std::collections::HashMap; use std::path::Path; use std::sync::Arc; /// GuildMap defines the guild-map type. /// It is basically a HashMap from a GuildId to a data structure. pub type GuildMap = HashMap; /// The generic DB type we will be using. pub struct DB(std::marker::PhantomData); impl serenity::prelude::TypeMapKey for DB { type Value = Arc>; } impl DB where for<'de> T: Deserialize<'de>, { /// Insert into a ShareMap. pub fn insert_into(data: &mut ShareMap, path: impl AsRef) -> Result<(), Error> { let db = FileDatabase::::from_path(path, T::default())?; db.load().or_else(|e| { dbg!(e); db.save() })?; data.insert::>(Arc::new(db)); Ok(()) } /// Open a previously inserted DB. pub fn open(data: &ShareMap) -> DBWriteGuard { data.get::().expect("DB initialized").clone().into() } } /// The write guard for our FileDatabase. /// It wraps the FileDatabase in a write-on-drop lock. #[derive(Debug)] pub struct DBWriteGuard(Arc>) where T: Send + Sync + Clone + std::fmt::Debug + Serialize + DeserializeOwned; impl From>> for DBWriteGuard where T: Send + Sync + Clone + std::fmt::Debug + Serialize + DeserializeOwned, { fn from(v: Arc>) -> Self { DBWriteGuard(v) } } impl DBWriteGuard where T: Send + Sync + Clone + std::fmt::Debug + Serialize + DeserializeOwned, { /// Borrows the FileDatabase. pub fn borrow(&self) -> Result, rustbreak::RustbreakError> { (*self).0.borrow_data() } /// Borrows the FileDatabase for writing. pub fn borrow_mut(&self) -> Result, rustbreak::RustbreakError> { (*self).0.borrow_data_mut() } } impl Drop for DBWriteGuard where T: Send + Sync + Clone + std::fmt::Debug + Serialize + DeserializeOwned, { fn drop(&mut self) { if let Err(e) = self.0.save() { dbg!(e); } } }