summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-03-11 15:34:47 +0800
committer魏曹先生 <1992414357@qq.com>2026-03-11 15:34:47 +0800
commit8b38e22525adcafecd8b50daf041a1dc2d672d0b (patch)
treeb5c012dbbdd6975f405105b778d0ba9354a21233 /utils
parente49128388e3b2f73523d82bf7f16fa1eae019c37 (diff)
Replace cfg_file with new config system
Diffstat (limited to 'utils')
-rw-r--r--utils/cfg_file/Cargo.toml23
-rw-r--r--utils/cfg_file/cfg_file_derive/Cargo.toml11
-rw-r--r--utils/cfg_file/cfg_file_derive/src/lib.rs130
-rw-r--r--utils/cfg_file/cfg_file_test/Cargo.toml9
-rw-r--r--utils/cfg_file/cfg_file_test/src/lib.rs95
-rw-r--r--utils/cfg_file/src/config.rs263
-rw-r--r--utils/cfg_file/src/lib.rs7
7 files changed, 0 insertions, 538 deletions
diff --git a/utils/cfg_file/Cargo.toml b/utils/cfg_file/Cargo.toml
deleted file mode 100644
index 0685329..0000000
--- a/utils/cfg_file/Cargo.toml
+++ /dev/null
@@ -1,23 +0,0 @@
-[package]
-name = "cfg_file"
-edition = "2024"
-version.workspace = true
-
-[features]
-default = ["derive"]
-derive = []
-
-[dependencies]
-cfg_file_derive = { path = "cfg_file_derive" }
-
-# Async
-tokio = { version = "1.48.0", features = ["full"] }
-async-trait = "0.1.89"
-
-# Serialization
-serde = { version = "1.0.228", features = ["derive"] }
-serde_yaml = "0.9.34"
-serde_json = "1.0.145"
-ron = "0.11.0"
-toml = "0.9.8"
-bincode2 = "2.0.1"
diff --git a/utils/cfg_file/cfg_file_derive/Cargo.toml b/utils/cfg_file/cfg_file_derive/Cargo.toml
deleted file mode 100644
index ce5e77f..0000000
--- a/utils/cfg_file/cfg_file_derive/Cargo.toml
+++ /dev/null
@@ -1,11 +0,0 @@
-[package]
-name = "cfg_file_derive"
-edition = "2024"
-version.workspace = true
-
-[lib]
-proc-macro = true
-
-[dependencies]
-syn = { version = "2.0", features = ["full", "extra-traits"] }
-quote = "1.0"
diff --git a/utils/cfg_file/cfg_file_derive/src/lib.rs b/utils/cfg_file/cfg_file_derive/src/lib.rs
deleted file mode 100644
index e916311..0000000
--- a/utils/cfg_file/cfg_file_derive/src/lib.rs
+++ /dev/null
@@ -1,130 +0,0 @@
-extern crate proc_macro;
-
-use proc_macro::TokenStream;
-use quote::quote;
-use syn::parse::ParseStream;
-use syn::{Attribute, DeriveInput, Expr, parse_macro_input};
-/// # Macro - ConfigFile
-///
-/// ## Usage
-///
-/// Use `#[derive(ConfigFile)]` to derive the ConfigFile trait for a struct
-///
-/// Specify the default storage path via `#[cfg_file(path = "...")]`
-///
-/// ## About the `cfg_file` attribute macro
-///
-/// Use `#[cfg_file(path = "string")]` to specify the configuration file path
-///
-/// Or use `#[cfg_file(path = constant_expression)]` to specify the configuration file path
-///
-/// ## Path Rules
-///
-/// Paths starting with `"./"`: relative to the current working directory
-///
-/// Other paths: treated as absolute paths
-///
-/// When no path is specified: use the struct name + ".json" as the default filename (e.g., `my_struct.json`)
-///
-/// ## Example
-/// ```ignore
-/// #[derive(ConfigFile)]
-/// #[cfg_file(path = "./config.json")]
-/// struct AppConfig;
-/// ```
-#[proc_macro_derive(ConfigFile, attributes(cfg_file))]
-pub fn derive_config_file(input: TokenStream) -> TokenStream {
- let input = parse_macro_input!(input as DeriveInput);
- let name = &input.ident;
-
- // Process 'cfg_file'
- let path_expr = match find_cfg_file_path(&input.attrs) {
- Some(PathExpr::StringLiteral(path)) => {
- if let Some(path_str) = path.strip_prefix("./") {
- quote! {
- std::env::current_dir()?.join(#path_str)
- }
- } else {
- // Using Absolute Path
- quote! {
- std::path::PathBuf::from(#path)
- }
- }
- }
- Some(PathExpr::PathExpression(path_expr)) => {
- // For path expressions (constants), generate code that references the constant
- quote! {
- std::path::PathBuf::from(#path_expr)
- }
- }
- None => {
- let default_file = to_snake_case(&name.to_string()) + ".json";
- quote! {
- std::env::current_dir()?.join(#default_file)
- }
- }
- };
-
- let expanded = quote! {
- impl cfg_file::config::ConfigFile for #name {
- type DataType = #name;
-
- fn default_path() -> Result<std::path::PathBuf, std::io::Error> {
- Ok(#path_expr)
- }
- }
- };
-
- TokenStream::from(expanded)
-}
-
-enum PathExpr {
- StringLiteral(String),
- PathExpression(syn::Expr),
-}
-
-fn find_cfg_file_path(attrs: &[Attribute]) -> Option<PathExpr> {
- for attr in attrs {
- if attr.path().is_ident("cfg_file") {
- let parser = |meta: ParseStream| {
- let path_meta: syn::MetaNameValue = meta.parse()?;
- if path_meta.path.is_ident("path") {
- match &path_meta.value {
- // String literal case: path = "./vault.toml"
- Expr::Lit(expr_lit) if matches!(expr_lit.lit, syn::Lit::Str(_)) => {
- if let syn::Lit::Str(lit_str) = &expr_lit.lit {
- return Ok(PathExpr::StringLiteral(lit_str.value()));
- }
- }
- // Path expression case: path = SERVER_FILE_VAULT or crate::constants::SERVER_FILE_VAULT
- expr @ (Expr::Path(_) | Expr::Macro(_)) => {
- return Ok(PathExpr::PathExpression(expr.clone()));
- }
- _ => {}
- }
- }
- Err(meta.error("expected `path = \"...\"` or `path = CONSTANT`"))
- };
-
- if let Ok(path_expr) = attr.parse_args_with(parser) {
- return Some(path_expr);
- }
- }
- }
- None
-}
-
-fn to_snake_case(s: &str) -> String {
- let mut snake = String::new();
- for (i, c) in s.chars().enumerate() {
- if c.is_uppercase() {
- if i != 0 {
- snake.push('_');
- }
- snake.push(c.to_ascii_lowercase());
- } else {
- snake.push(c);
- }
- }
- snake
-}
diff --git a/utils/cfg_file/cfg_file_test/Cargo.toml b/utils/cfg_file/cfg_file_test/Cargo.toml
deleted file mode 100644
index 5db1010..0000000
--- a/utils/cfg_file/cfg_file_test/Cargo.toml
+++ /dev/null
@@ -1,9 +0,0 @@
-[package]
-name = "cfg_file_test"
-version = "0.1.0"
-edition = "2024"
-
-[dependencies]
-cfg_file = { path = "../../cfg_file", features = ["default"] }
-tokio = { version = "1.48.0", features = ["full"] }
-serde = { version = "1.0.228", features = ["derive"] }
diff --git a/utils/cfg_file/cfg_file_test/src/lib.rs b/utils/cfg_file/cfg_file_test/src/lib.rs
deleted file mode 100644
index f70d00d..0000000
--- a/utils/cfg_file/cfg_file_test/src/lib.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-#[cfg(test)]
-mod test_cfg_file {
- use cfg_file::ConfigFile;
- use cfg_file::config::ConfigFile;
- use serde::{Deserialize, Serialize};
- use std::collections::HashMap;
-
- #[derive(ConfigFile, Deserialize, Serialize, Default)]
- #[cfg_file(path = "./.temp/example_cfg.toml")]
- struct ExampleConfig {
- name: String,
- age: i32,
- hobby: Vec<String>,
- secret: HashMap<String, String>,
- }
-
- #[derive(ConfigFile, Deserialize, Serialize, Default)]
- #[cfg_file(path = "./.temp/example_bincode.bcfg")]
- struct ExampleBincodeConfig {
- name: String,
- age: i32,
- hobby: Vec<String>,
- secret: HashMap<String, String>,
- }
-
- #[tokio::test]
- async fn test_config_file_serialization() {
- let mut example = ExampleConfig {
- name: "Weicao".to_string(),
- age: 22,
- hobby: ["Programming", "Painting"]
- .iter()
- .map(|m| m.to_string())
- .collect(),
- secret: HashMap::new(),
- };
- let secret_no_comments =
- "Actually, I'm really too lazy to write comments, documentation, and unit tests.";
- example
- .secret
- .entry("No comments".to_string())
- .insert_entry(secret_no_comments.to_string());
-
- let secret_peek = "Of course, it's peeking at you who's reading the source code.";
- example
- .secret
- .entry("Peek".to_string())
- .insert_entry(secret_peek.to_string());
-
- ExampleConfig::write(&example).await.unwrap(); // Write to default path.
-
- // Read from default path.
- let read_cfg = ExampleConfig::read().await.unwrap();
- assert_eq!(read_cfg.name, "Weicao");
- assert_eq!(read_cfg.age, 22);
- assert_eq!(read_cfg.hobby, vec!["Programming", "Painting"]);
- assert_eq!(read_cfg.secret["No comments"], secret_no_comments);
- assert_eq!(read_cfg.secret["Peek"], secret_peek);
- }
-
- #[tokio::test]
- async fn test_bincode_config_file_serialization() {
- let mut example = ExampleBincodeConfig {
- name: "Weicao".to_string(),
- age: 22,
- hobby: ["Programming", "Painting"]
- .iter()
- .map(|m| m.to_string())
- .collect(),
- secret: HashMap::new(),
- };
- let secret_no_comments =
- "Actually, I'm really too lazy to write comments, documentation, and unit tests.";
- example
- .secret
- .entry("No comments".to_string())
- .insert_entry(secret_no_comments.to_string());
-
- let secret_peek = "Of course, it's peeking at you who's reading the source code.";
- example
- .secret
- .entry("Peek".to_string())
- .insert_entry(secret_peek.to_string());
-
- ExampleBincodeConfig::write(&example).await.unwrap(); // Write to default path.
-
- // Read from default path.
- let read_cfg = ExampleBincodeConfig::read().await.unwrap();
- assert_eq!(read_cfg.name, "Weicao");
- assert_eq!(read_cfg.age, 22);
- assert_eq!(read_cfg.hobby, vec!["Programming", "Painting"]);
- assert_eq!(read_cfg.secret["No comments"], secret_no_comments);
- assert_eq!(read_cfg.secret["Peek"], secret_peek);
- }
-}
diff --git a/utils/cfg_file/src/config.rs b/utils/cfg_file/src/config.rs
deleted file mode 100644
index d3f5477..0000000
--- a/utils/cfg_file/src/config.rs
+++ /dev/null
@@ -1,263 +0,0 @@
-use async_trait::async_trait;
-use bincode2;
-use ron;
-use serde::{Deserialize, Serialize};
-use std::{
- borrow::Cow,
- env::current_dir,
- io::Error,
- path::{Path, PathBuf},
-};
-use tokio::{fs, io::AsyncReadExt};
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-enum ConfigFormat {
- Yaml,
- Toml,
- Ron,
- Json,
- Bincode,
-}
-
-impl ConfigFormat {
- fn from_filename(filename: &str) -> Option<Self> {
- if filename.ends_with(".yaml") || filename.ends_with(".yml") {
- Some(Self::Yaml)
- } else if filename.ends_with(".toml") || filename.ends_with(".tom") {
- Some(Self::Toml)
- } else if filename.ends_with(".ron") {
- Some(Self::Ron)
- } else if filename.ends_with(".json") {
- Some(Self::Json)
- } else if filename.ends_with(".bcfg") {
- Some(Self::Bincode)
- } else {
- None
- }
- }
-}
-
-/// # Trait - ConfigFile
-///
-/// Used to implement more convenient persistent storage functionality for structs
-///
-/// This trait requires the struct to implement Default and serde's Serialize and Deserialize traits
-///
-/// ## Implementation
-///
-/// ```ignore
-/// // Your struct
-/// #[derive(Default, Serialize, Deserialize)]
-/// struct YourData;
-///
-/// impl ConfigFile for YourData {
-/// type DataType = YourData;
-///
-/// // Specify default path
-/// fn default_path() -> Result<PathBuf, Error> {
-/// Ok(current_dir()?.join("data.json"))
-/// }
-/// }
-/// ```
-///
-/// > **Using derive macro**
-/// >
-/// > We provide the derive macro `#[derive(ConfigFile)]`
-/// >
-/// > You can implement this trait more quickly, please check the module cfg_file::cfg_file_derive
-///
-#[async_trait]
-pub trait ConfigFile: Serialize + for<'a> Deserialize<'a> + Default {
- type DataType: Serialize + for<'a> Deserialize<'a> + Default + Send + Sync;
-
- fn default_path() -> Result<PathBuf, Error>;
-
- /// # Read from default path
- ///
- /// Read data from the path specified by default_path()
- ///
- /// ```ignore
- /// fn main() -> Result<(), std::io::Error> {
- /// let data = YourData::read().await?;
- /// }
- /// ```
- async fn read() -> Result<Self::DataType, std::io::Error>
- where
- Self: Sized + Send + Sync,
- {
- let path = Self::default_path()?;
- Self::read_from(path).await
- }
-
- /// # Read from the given path
- ///
- /// Read data from the path specified by the path parameter
- ///
- /// ```ignore
- /// fn main() -> Result<(), std::io::Error> {
- /// let data_path = current_dir()?.join("data.json");
- /// let data = YourData::read_from(data_path).await?;
- /// }
- /// ```
- async fn read_from(path: impl AsRef<Path> + Send) -> Result<Self::DataType, std::io::Error>
- where
- Self: Sized + Send + Sync,
- {
- let path = path.as_ref();
- let cwd = current_dir()?;
- let file_path = cwd.join(path);
-
- // Check if file exists
- if fs::metadata(&file_path).await.is_err() {
- return Err(std::io::Error::new(
- std::io::ErrorKind::NotFound,
- "Config file not found",
- ));
- }
-
- // Determine file format first
- let format = file_path
- .file_name()
- .and_then(|name| name.to_str())
- .and_then(ConfigFormat::from_filename)
- .unwrap_or(ConfigFormat::Bincode); // Default to Bincode
-
- // Deserialize based on format
- let result = match format {
- ConfigFormat::Yaml => {
- let mut file = fs::File::open(&file_path).await?;
- let mut contents = String::new();
- file.read_to_string(&mut contents).await?;
- serde_yaml::from_str(&contents)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?
- }
- ConfigFormat::Toml => {
- let mut file = fs::File::open(&file_path).await?;
- let mut contents = String::new();
- file.read_to_string(&mut contents).await?;
- toml::from_str(&contents)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?
- }
- ConfigFormat::Ron => {
- let mut file = fs::File::open(&file_path).await?;
- let mut contents = String::new();
- file.read_to_string(&mut contents).await?;
- ron::from_str(&contents)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?
- }
- ConfigFormat::Json => {
- let mut file = fs::File::open(&file_path).await?;
- let mut contents = String::new();
- file.read_to_string(&mut contents).await?;
- serde_json::from_str(&contents)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?
- }
- ConfigFormat::Bincode => {
- // For Bincode, we need to read the file as bytes directly
- let bytes = fs::read(&file_path).await?;
- bincode2::deserialize(&bytes)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?
- }
- };
-
- Ok(result)
- }
-
- /// # Write to default path
- ///
- /// Write data to the path specified by default_path()
- ///
- /// ```ignore
- /// fn main() -> Result<(), std::io::Error> {
- /// let data = YourData::default();
- /// YourData::write(&data).await?;
- /// }
- /// ```
- async fn write(val: &Self::DataType) -> Result<(), std::io::Error>
- where
- Self: Sized + Send + Sync,
- {
- let path = Self::default_path()?;
- Self::write_to(val, path).await
- }
- /// # Write to the given path
- ///
- /// Write data to the path specified by the path parameter
- ///
- /// ```ignore
- /// fn main() -> Result<(), std::io::Error> {
- /// let data = YourData::default();
- /// let data_path = current_dir()?.join("data.json");
- /// YourData::write_to(&data, data_path).await?;
- /// }
- /// ```
- async fn write_to(
- val: &Self::DataType,
- path: impl AsRef<Path> + Send,
- ) -> Result<(), std::io::Error>
- where
- Self: Sized + Send + Sync,
- {
- let path = path.as_ref();
-
- if let Some(parent) = path.parent()
- && !parent.exists()
- {
- tokio::fs::create_dir_all(parent).await?;
- }
-
- let cwd = current_dir()?;
- let file_path = cwd.join(path);
-
- // Determine file format
- let format = file_path
- .file_name()
- .and_then(|name| name.to_str())
- .and_then(ConfigFormat::from_filename)
- .unwrap_or(ConfigFormat::Bincode); // Default to Bincode
-
- match format {
- ConfigFormat::Yaml => {
- let contents = serde_yaml::to_string(val)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
- fs::write(&file_path, contents).await?
- }
- ConfigFormat::Toml => {
- let contents = toml::to_string(val)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
- fs::write(&file_path, contents).await?
- }
- ConfigFormat::Ron => {
- let mut pretty_config = ron::ser::PrettyConfig::new();
- pretty_config.new_line = Cow::from("\n");
- pretty_config.indentor = Cow::from(" ");
-
- let contents = ron::ser::to_string_pretty(val, pretty_config)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
- fs::write(&file_path, contents).await?
- }
- ConfigFormat::Json => {
- let contents = serde_json::to_string(val)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
- fs::write(&file_path, contents).await?
- }
- ConfigFormat::Bincode => {
- let bytes = bincode2::serialize(val)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
- fs::write(&file_path, bytes).await?
- }
- }
- Ok(())
- }
-
- /// Check if the file returned by `default_path` exists
- fn exist() -> bool
- where
- Self: Sized + Send + Sync,
- {
- let Ok(path) = Self::default_path() else {
- return false;
- };
- path.exists()
- }
-}
diff --git a/utils/cfg_file/src/lib.rs b/utils/cfg_file/src/lib.rs
deleted file mode 100644
index 72246e7..0000000
--- a/utils/cfg_file/src/lib.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#[cfg(feature = "derive")]
-extern crate cfg_file_derive;
-
-#[cfg(feature = "derive")]
-pub use cfg_file_derive::*;
-
-pub mod config;