diff options
| author | 魏曹先生 <1992414357@qq.com> | 2025-09-12 00:34:17 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2025-09-12 00:34:17 +0800 |
| commit | bb5b15b5abba1caf0fa8d8861c118cd73edf76d0 (patch) | |
| tree | f971fdc187441037949345f41301d85e2ec65602 /crates/utils | |
| parent | 75b747a2569ad94381f9dd0b26780c3759d9f637 (diff) | |
Add Crate `cfg_file`
.../utils/cfg_file
.../cfg_file/cfg_file_derive
.../cfg_file/cfg_file_example
Diffstat (limited to 'crates/utils')
| -rw-r--r-- | crates/utils/cfg_file/Cargo.toml | 17 | ||||
| -rw-r--r-- | crates/utils/cfg_file/cfg_file_derive/Cargo.toml | 11 | ||||
| -rw-r--r-- | crates/utils/cfg_file/cfg_file_derive/src/lib.rs | 87 | ||||
| -rw-r--r-- | crates/utils/cfg_file/cfg_file_example/Cargo.toml | 10 | ||||
| -rw-r--r-- | crates/utils/cfg_file/cfg_file_example/src/main.rs | 45 | ||||
| -rw-r--r-- | crates/utils/cfg_file/src/lib.rs | 1 |
6 files changed, 171 insertions, 0 deletions
diff --git a/crates/utils/cfg_file/Cargo.toml b/crates/utils/cfg_file/Cargo.toml new file mode 100644 index 0000000..9d9a6b8 --- /dev/null +++ b/crates/utils/cfg_file/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "cfg_file" +edition = "2024" +version.workspace = true + +[dependencies] + +# Async +tokio = { version = "1.46.1", features = ["full"] } +async-trait = "0.1.88" + +# Serialization +serde = { version = "1.0.219", features = ["derive"] } +serde_yaml = "0.9.34" +serde_json = "1.0.140" +ron = "0.11.0" +toml = "0.9.0" diff --git a/crates/utils/cfg_file/cfg_file_derive/Cargo.toml b/crates/utils/cfg_file/cfg_file_derive/Cargo.toml new file mode 100644 index 0000000..ce5e77f --- /dev/null +++ b/crates/utils/cfg_file/cfg_file_derive/Cargo.toml @@ -0,0 +1,11 @@ +[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/crates/utils/cfg_file/cfg_file_derive/src/lib.rs b/crates/utils/cfg_file/cfg_file_derive/src/lib.rs new file mode 100644 index 0000000..3a6d0fd --- /dev/null +++ b/crates/utils/cfg_file/cfg_file_derive/src/lib.rs @@ -0,0 +1,87 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; +use quote::quote; +use syn::parse::ParseStream; +use syn::{ + parse_macro_input, + DeriveInput, + Attribute +}; + +#[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(path) => { + if path.starts_with("./") { + let path_str = &path[2..]; + quote! { + std::env::current_dir()?.join(#path_str) + } + } else { + // Using Absolute Path + quote! { + std::path::PathBuf::from(#path) + } + } + } + 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) +} + +fn find_cfg_file_path(attrs: &[Attribute]) -> Option<String> { + 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") { + if let syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(lit), .. }) = path_meta.value { + return Ok(lit.value()); + } + } + Err(meta.error("expected `path = \"...\"`")) + }; + + if let Ok(path) = attr.parse_args_with(parser) { + return Some(path); + } + } + } + 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 +}
\ No newline at end of file diff --git a/crates/utils/cfg_file/cfg_file_example/Cargo.toml b/crates/utils/cfg_file/cfg_file_example/Cargo.toml new file mode 100644 index 0000000..932bc31 --- /dev/null +++ b/crates/utils/cfg_file/cfg_file_example/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "cfg_file_example" +edition = "2024" +version.workspace = true + +[dependencies] +cfg_file = { path = "../../cfg_file" } +cfg_file_derive = { path = "../cfg_file_derive" } +tokio = { version = "1.46.1", features = ["full"] } +serde = { version = "1.0.219", features = ["derive"] }
\ No newline at end of file diff --git a/crates/utils/cfg_file/cfg_file_example/src/main.rs b/crates/utils/cfg_file/cfg_file_example/src/main.rs new file mode 100644 index 0000000..aacef4e --- /dev/null +++ b/crates/utils/cfg_file/cfg_file_example/src/main.rs @@ -0,0 +1,45 @@ +use std::collections::HashMap; +use cfg_file_derive::ConfigFile; +use serde::{Deserialize, Serialize}; +use cfg_file::config::ConfigFile; + +#[derive(ConfigFile, Deserialize, Serialize, Default)] +#[cfg_file(path = "./.temp/example/cfg_file/example_cfg.toml")] +struct ExampleConfig { + name: String, + age: i32, + hobby: Vec<String>, + secret: HashMap<String, String>, +} + +#[tokio::main] +async fn main() { + let mut example = ExampleConfig { + name: "Weicao".to_string(), + age: 22, + hobby: vec![ "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; // Write to default path. + + // Read from default path. + let read_cfg = ExampleConfig::read().await; + 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/crates/utils/cfg_file/src/lib.rs b/crates/utils/cfg_file/src/lib.rs new file mode 100644 index 0000000..a105933 --- /dev/null +++ b/crates/utils/cfg_file/src/lib.rs @@ -0,0 +1 @@ +pub mod config;
\ No newline at end of file |
