Crates.io | dynarg |
lib.rs | dynarg |
version | 2.1.4 |
source | src |
created_at | 2022-12-14 09:37:00.309094 |
updated_at | 2023-01-24 04:35:32.16085 |
description | A simple mechanism for dynamic robust argument handling |
homepage | |
repository | https://github.com/alxpettit/dynarg |
max_upload_size | |
id | 736486 |
size | 41,758 |
A simple dynamic argument system
Have you ever wanted to have multiple functions with the same signature, but with very different purposes and behavior?
Regardless, you probably want an API that can:
If any of this applies to you, this is a library to consider. Note that for very high-performance applications, it might be better to roll your own custom use case with a Vec (ideally recycled!) of enum, to avoid dynamic dispatch.
This API is at this point considered stable and reasonably mature. It is forbid_unsafe
, and written in pure Rust.
use dynarg::Args;
fn main() {
// Creating Args object
let mut args = Args::new();
// Inserting a string type
args.insert_string("greeting", String::from("hello world"));
// Inserting an i32 type
args.insert_i32("meaning_of_life", 42);
// There's a lot more types where that came from, BTW :)
// (In fact, you can use any type that implements `Any`,
// which... I think should be any?)
// Retrieving string type
let out = args.get_string("greeting").unwrap();
println!("{}", out);
// Retrieving i32
let meaning_of_life = args.get_i32("meaning_of_life").unwrap();
println!("The meaning of life is: {}", meaning_of_life);
}
use dynarg::Args;
fn main() {
// Creating Args object
let mut args = Args::new();
// Inserting a string type
args.insert_string("greeting", String::from("hello world"));
// Inserting an i32 type
args.insert_i32("meaning_of_life", 42);
// There's a lot more types where that came from, BTW :)
// (In fact, you can use any type that implements `Any`, which... I think should be any?)
// Retrieving string type (while marking used flag!)
let out = args.poke_string("greeting").unwrap();
println!("{}", out);
// Retrieving i32 (also while marking used flag!)
let meaning_of_life = args.poke_i32("meaning_of_life").unwrap();
println!("The meaning of life is: {}", meaning_of_life);
// NOTE: the difference between poke and poke_* functions, and get and get_,
// is that poke marks the status as used.
// Note that this only exists if `used` feature is enabled for library.
// Explicitly marking status is used is useful for sanity checking -- e.g.
// Checking used status of args is useful for catching
// what would otherwise be silent or hard-to-catch errors
if args.all_used() {
println!("All used! :3");
} else {
for used_arg_name in args.iter_not_used_name() {
println!("Arg: \"{}\" not used", used_arg_name);
}
}
}
use dynarg::*;
/// Where normally you'd need to have a fixed set of arguments,
/// each of which would be roughly fixed types
/// -- you can dynamically push arguments on the fly instead.
/// This is useful when you need a consistent function signature
/// for different types of functions,
/// each needing different arguments
fn draw(args: &mut Args) {
if let Ok(greeting) = args.poke_string("greeting") {
println!("{} world", greeting);
}
if let Ok(arg) = args.poke::<Fruit>("fruit_to_draw") {
println!("I will draw {}!", arg.0);
if let Ok(size) = args.poke::<f32>("size") {
println!("with a size of {}", size);
}
} else {
panic!("Nothing to draw D:");
}
}
/// A custom struct as an example
struct Fruit<'a>(&'a str);
fn main() {
let mut args = Args::default();
let apple = Fruit("apple");
// This is how you add arguments
args.insert("fruit_to_draw", Box::new(apple));
args.insert("size", Box::new(5.2f32));
let greeting = String::from("henlo");
args.insert_string("greeting", greeting);
draw(&mut args);
if !args.all_used() {
println!("Warning! I didn't use all my arguments D:");
}
// Clear all the used flags on args
args.reset_used_status();
}
PRs welcome :)
Option
s with Result
s such that it's possible to identify whether the argument name didn't exist, or the type was wrongsnafu
get_string()
, get_int()
)used()
functionality.