caretta-sync/core/src/config/mod.rs

113 lines
3.1 KiB
Rust
Raw Normal View History

2025-06-18 08:36:01 +09:00
pub mod error;
2025-06-19 07:24:44 +09:00
mod storage;
mod p2p;
2025-05-24 06:11:00 +09:00
2025-05-30 09:26:47 +09:00
use std::path::Path;
2025-07-05 10:30:55 +09:00
use crate::{utils::{emptiable::Emptiable, mergeable::Mergeable}};
2025-06-18 08:36:01 +09:00
pub use error::ConfigError;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
2025-05-30 09:26:47 +09:00
use tokio::{fs::File, io::{AsyncReadExt, AsyncWriteExt}};
2025-06-19 07:24:44 +09:00
pub use storage::{StorageConfig, PartialStorageConfig};
pub use p2p::{P2pConfig, PartialP2pConfig};
2025-06-18 08:36:01 +09:00
2025-07-04 08:05:43 +09:00
pub trait Config: TryFrom<Self::PartialConfig>{
type PartialConfig: PartialConfig<Config = Self>;
}
pub trait PartialConfig: Emptiable + From<Self::Config> + Mergeable {
type Config: Config<PartialConfig = Self>;
}
2025-07-05 10:30:55 +09:00
pub trait BaseConfig: DeserializeOwned + Serialize {
2025-07-04 08:05:43 +09:00
fn new() -> Self;
2025-06-19 07:24:44 +09:00
fn from_toml(s: &str) -> Result<Self, toml::de::Error> {
toml::from_str(s)
}
fn into_toml(&self) -> Result<String, toml::ser::Error> {
toml::to_string(self)
}
2025-07-05 10:30:55 +09:00
async fn read_or_create<T>(path: T) -> Result<Self, ConfigError>
2025-06-18 08:36:01 +09:00
where
T: AsRef<Path>
{
if !path.as_ref().exists() {
Self::new().write_to(&path).await?;
}
Self::read_from(&path).await
}
2025-07-05 10:30:55 +09:00
async fn read_from<T>(path:T) -> Result<Self, ConfigError>
2025-06-18 08:36:01 +09:00
where
T: AsRef<Path>
{
let mut file = File::open(path.as_ref()).await?;
let mut content = String::new();
file.read_to_string(&mut content).await?;
let config: Self = toml::from_str(&content)?;
Ok(config)
}
2025-07-05 10:30:55 +09:00
async fn write_to<T>(&self, path:T) -> Result<(), ConfigError>
2025-06-18 08:36:01 +09:00
where
T: AsRef<Path>
{
if !path.as_ref().exists() {
if let Some(x) = path.as_ref().parent() {
std::fs::create_dir_all(x)?;
};
let _ = File::create(&path).await?;
}
let mut file = File::create(&path).await?;
file.write_all(toml::to_string(self)?.as_bytes()).await?;
Ok(())
}
2025-06-19 07:24:44 +09:00
}
#[cfg(test)]
mod tests {
use serde::{Deserialize, Serialize};
2025-07-04 08:05:43 +09:00
use crate::{tests::test_toml_serialize_deserialize, utils::{emptiable::Emptiable, mergeable::Mergeable}};
2025-06-19 07:24:44 +09:00
use super::{p2p::{P2pConfig, PartialP2pConfig}, PartialConfig};
#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct TestConfig {
p2p: Option<PartialP2pConfig>
}
2025-07-04 08:05:43 +09:00
impl Default for TestConfig {
2025-06-19 07:24:44 +09:00
fn default() -> Self {
Self {
p2p: Some(PartialP2pConfig::default()),
}
}
2025-07-04 08:05:43 +09:00
}
impl Emptiable for TestConfig {
2025-06-19 07:24:44 +09:00
fn empty() -> Self {
Self {
p2p: None,
}
}
fn is_empty(&self) -> bool {
self.p2p.is_none()
}
2025-07-04 08:05:43 +09:00
}
impl Mergeable for TestConfig {
2025-06-19 07:24:44 +09:00
fn merge(&mut self, other: Self) {
if let Some(p2p) = other.p2p {
self.p2p = Some(p2p);
}
}
}
#[tokio::test]
async fn test_p2p_config_serialize_deserialize() {
test_toml_serialize_deserialize(TestConfig::empty());
test_toml_serialize_deserialize(TestConfig::default());
assert_eq!(TestConfig::empty(), toml::from_str("").unwrap());
assert_eq!("", &toml::to_string(&TestConfig::empty()).unwrap());
}
2025-06-18 08:36:01 +09:00
}