diff --git a/Cargo.toml b/Cargo.toml index 5558287..d568e75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,3 +49,11 @@ overflow-checks = false [[bench]] name = "bench_apis" harness = false + +[[example]] +name = "clap_mini" +path = "examples/rust/clap_mini.rs" + +[[example]] +name = "clap_layered" +path = "examples/rust/clap_layered.rs" \ No newline at end of file diff --git a/examples/rust/cfg.toml b/examples/rust/cfg.toml new file mode 100644 index 0000000..4ea687b --- /dev/null +++ b/examples/rust/cfg.toml @@ -0,0 +1,2 @@ +[example] +param1 = "from config" \ No newline at end of file diff --git a/examples/rust/clap_layered.rs b/examples/rust/clap_layered.rs new file mode 100644 index 0000000..a1df51d --- /dev/null +++ b/examples/rust/clap_layered.rs @@ -0,0 +1,49 @@ +use std::path::Path; + +use clap::Parser; +use config::{self, File}; +use hyperparameter::*; + +/// Defines the command-line arguments for the application. +#[derive(Parser)] +#[command(after_long_help=generate_params_help())] +struct CommandLineArgs { + /// Specifies hyperparameters in the format `-D key=value` via the command line. + #[arg(short = 'D', long)] + define: Vec, + + /// Specifies the configuration file path. + #[arg(short = 'C', long, default_value = "examples/rust/cfg.toml")] + config: String, +} + +fn main() { + let args = CommandLineArgs::parse(); + let config_path = Path::new(&args.config); + let config = config::Config::builder() + .add_source(File::from(config_path)) + .build() + .expect("Failed to load configuration file."); // Improved error handling + + // No scope + println!( + "param1={} // Outside any specific scope", + get_param!(example.param1, "default".to_string()) + ); + + with_params! { // Scope with configuration file parameters + params config.param_scope(); + + println!("param1={} // Within configuration file scope", get_param!(example.param1, "default".to_string())); + with_params! { // Scope with command-line arguments + params ParamScope::from(&args.define); + + println!("param1={} // Within command-line arguments scope", get_param!(example.param1, "default".to_string(), "Example param1")); + with_params! { // User-defined scope + set example.param1= "scoped".to_string(); + + println!("param1={} // Within user-defined scope", get_param!(example.param1, "default".to_string())); + } + } + } +} diff --git a/examples/rust/clap_mini.rs b/examples/rust/clap_mini.rs new file mode 100644 index 0000000..37b4862 --- /dev/null +++ b/examples/rust/clap_mini.rs @@ -0,0 +1,22 @@ +use clap::Parser; +use hyperparameter::*; + +/// Defines the command-line arguments for the application. +#[derive(Parser)] +#[command(after_long_help=generate_params_help())] +struct CommandLineArgs { + /// Specifies hyperparameters in the format `-D key=value` via the command line. + #[arg(short = 'D', long)] + define: Vec, +} + +fn main() { + let args = CommandLineArgs::parse(); + with_params! { + params ParamScope::from(&args.define); + // Retrieves `example.param1` with a default value of `1` if not specified. + println!("param1={}", get_param!(example.param1, 1)); + // Displays a help message when ` --help` is executed. + println!("param2={}", get_param!(example.param2, false, "Example param2")); + } +} \ No newline at end of file diff --git a/src/api.rs b/src/api.rs index b3dfa47..9573d28 100644 --- a/src/api.rs +++ b/src/api.rs @@ -7,7 +7,7 @@ use crate::storage::{ use crate::value::{Value, EMPTY}; use crate::xxh::XXHashable; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum ParamScope { Nothing, Just(Tree), @@ -180,9 +180,7 @@ macro_rules! get_param { { const CONST_HELP: &str = $help; #[::linkme::distributed_slice(PARAMS)] - static help: (&str, &str) = ( - CONST_KEY, CONST_HELP - ); + static help: (&str, &str) = (CONST_KEY, CONST_HELP); } THREAD_STORAGE.with(|ts| ts.borrow_mut().get_or_else(CONST_HASH, $default)) }}; @@ -242,6 +240,18 @@ macro_rules! with_params { with_params!(params $ps; $($body)*) }; + ( + params $ps:expr; + params $nested:expr; + + $($body:tt)* + ) => { + $ps.enter(); + let ret = with_params!(params $nested; $($body)*); + $ps.exit(); + ret + }; + ( get $name:ident = $($key:ident).+ or $default:expr; @@ -257,7 +267,6 @@ macro_rules! with_params { $($body:tt)* ) => { - $ps.enter(); let ret = { let $name = get_param!($($key).+, $default); @@ -266,7 +275,6 @@ macro_rules! with_params { }; $ps.exit(); ret - }; ( @@ -279,6 +287,11 @@ macro_rules! with_params { $ps.exit(); ret }}; + + ($($body:tt)*) => {{ + let ret = {$($body)*}; + ret + }}; } #[macro_export]