From eca7687439c2b6f804603de75501b6737a82e5a2 Mon Sep 17 00:00:00 2001 From: Vika Date: Thu, 15 Jun 2023 17:02:39 +0300 Subject: Database: use newtypes to represent settings This allows much for a cleaner and idiomatic settings interface. --- kittybox-rs/src/database/mod.rs | 92 ++++++++++++++++++++++++++++++++--------- 1 file changed, 73 insertions(+), 19 deletions(-) (limited to 'kittybox-rs/src/database/mod.rs') diff --git a/kittybox-rs/src/database/mod.rs b/kittybox-rs/src/database/mod.rs index 24cff38..2039ac0 100644 --- a/kittybox-rs/src/database/mod.rs +++ b/kittybox-rs/src/database/mod.rs @@ -1,6 +1,5 @@ #![warn(missing_docs)] use async_trait::async_trait; -use serde::{Deserialize, Serialize}; mod file; pub use crate::database::file::FileStorage; @@ -11,6 +10,8 @@ pub use crate::database::memory::MemoryStorage; pub use kittybox_util::MicropubChannel; +use self::settings::Setting; + /// Enum representing different errors that might occur during the database query. #[derive(Debug, Clone, Copy)] pub enum ErrorKind { @@ -33,17 +34,68 @@ pub enum ErrorKind { Other, } -/// Enum representing settings that might be stored in the site's database. -#[derive(Deserialize, Serialize, Debug, Clone, Copy)] -#[serde(rename_all = "snake_case")] -pub enum Settings { - /// The name of the website -- displayed in the header and the browser titlebar. - SiteName, -} +/// Settings that can be stored in the database. +pub mod settings { + mod private { + pub trait Sealed {} + } + /*#[derive(serde::Deserialize, serde::Serialize, Default)] + pub struct Settings { + pub site_name: SiteName, + pub webring: Webring + } + impl From for SiteName { + fn from(settings: Settings) -> Self { + settings.site_name + } + }*/ + + /// A trait for various settings that should be contained here. + /// + /// **Note**: this trait is sealed to prevent external + /// implementations, as it wouldn't make sense to add new settings + /// that aren't used by Kittybox itself. + pub trait Setting<'de>: private::Sealed + std::fmt::Debug + Default + Clone + serde::Serialize + serde::de::DeserializeOwned + /*From +*/ Send + Sync { + type Data: std::fmt::Debug + Send + Sync; + const ID: &'static str; + + /// Unwrap the setting type, returning owned data contained within. + fn into_inner(self) -> Self::Data; + /// Create a new instance of this type containing certain data. + fn new(data: Self::Data) -> Self; + } + + /// A website's title, shown in the header. + #[derive(Debug, serde::Deserialize, serde::Serialize, Clone, PartialEq, Eq)] + pub struct SiteName(String); + impl Default for SiteName { + fn default() -> Self { + Self("Kittybox".to_string()) + } + } + impl AsRef for SiteName { + fn as_ref(&self) -> &str { + self.0.as_str() + } + } + impl private::Sealed for SiteName {} + impl Setting<'_> for SiteName { + type Data = String; + const ID: &'static str = "site_name"; + + fn into_inner(self) -> String { + self.0 + } + fn new(data: Self::Data) -> Self { + Self(data) + } + } + impl SiteName { + fn from_str(data: &str) -> Self { + Self(data.to_owned()) + } + } -impl std::string::ToString for Settings { - fn to_string(&self) -> String { - serde_variant::to_variant_name(self).unwrap().to_string() } } @@ -248,14 +300,16 @@ pub trait Storage: std::fmt::Debug + Clone + Send + Sync { async fn delete_post(&self, url: &'_ str) -> Result<()>; /// Gets a setting from the setting store and passes the result. - async fn get_setting(&self, setting: Settings, user: &'_ str) -> Result; + async fn get_setting, 'a>(&'_ self, user: &'_ str) -> Result; /// Commits a setting to the setting store. - async fn set_setting(&self, setting: Settings, user: &'_ str, value: &'_ str) -> Result<()>; + async fn set_setting, 'a>(&self, user: &'_ str, value: S::Data) -> Result<()>; } #[cfg(test)] mod tests { + use super::settings; + use super::{MicropubChannel, Storage}; use serde_json::json; @@ -413,18 +467,18 @@ mod tests { async fn test_settings(backend: Backend) { backend - .set_setting( - crate::database::Settings::SiteName, + .set_setting::( "https://fireburn.ru/", - "Vika's Hideout", + "Vika's Hideout".to_owned() ) .await .unwrap(); assert_eq!( backend - .get_setting(crate::database::Settings::SiteName, "https://fireburn.ru/") - .await - .unwrap(), + .get_setting::("https://fireburn.ru/") + .await + .unwrap() + .as_ref(), "Vika's Hideout" ); } -- cgit 1.4.1