A collection of simple tools in Rust as Rust modules:
crate::progress::DumbProgressIndicator
:
A simple Iterator
wrapper that helps to show progress of iteration.crate::arg::DumbArgParser
:
A simple argument parser.
It can be useful for handling command line argument parsing for a Rust program.crate::json::DumbJsonProcessor
:
A simple JSON processor / stream parser, that processes input JSON (possibly streamed piece by piece).
Instead of returning the parsed JSON as some object; as soon as JSON entries are recognized,
the configured callback is called for those recognized JSON entries.crate::calc::DumbCalcProcessor
:
A simple infix calculation processor
It can be used to implement a simple calculator in Rust.crate::calculator::DumbCalculator
:
A simple calculator that accepts input keys acting like a real calculator.
It can be used to implement a simple calculator UI in Rust.crate::ltemp::DumbLineTemplate
:
A simple line template for formatting a line.
It can be usee for printing values as a line with some template.crate::lblscreen::DumbLineByLineScreen
:
A terminal / text-based “screen” update helper.
It is extended from crate::ltemp::DumbLineTemplate
, and should be helpful in managing the updates of the formatted lines that acts as a “screen”.DumbProgressIndicator
use rusty_dumb_tools::prelude::*;
pub fn try_simple_progress_range() {
for i in dpir!(0..6, name = "RANGE", desc = "demo iteration of range") {
println!(" i is {}", i);
thread::sleep(Duration::from_millis(1000));
}
}
Note that dpir
is a macro for wrapping the Range
(0..6
) into a DumbProgressIndicator
object, which implements Iterator
trait so that it can be used in for construct.
The output will be like
💠 RANGE: 1/6 🌑🌓🌕🌕🌕🌕🌕🌕🌕🌕 – demo iteration of range 💠 … i is 0
💠 RANGE: 2/6 🌑🌑🌑🌕🌕🌕🌕🌕🌕🌕 – demo iteration of range 💠 … i is 1
💠 RANGE: 3/6 🌑🌑🌑🌑🌑🌕🌕🌕🌕🌕 – demo iteration of range 💠 … i is 2
💠 RANGE: 4/6 🌑🌑🌑🌑🌑🌑🌓🌕🌕🌕 – demo iteration of range 💠 … i is 3
💠 RANGE: 5/6 🌑🌑🌑🌑🌑🌑🌑🌑🌕🌕 – demo iteration of range 💠 … i is 4
💠 RANGE: 6/6 🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑 – demo iteration of range 💠 … i is 5
use rusty_dumb_tools::prelude::*;
pub fn try_nested_progress() {
for i in dpir!(0..3, name = "RANGE") {
let items = vec![
String::from("apple"),
String::from("banana"),
String::from("orange"),
];
for item in dpi_iter!(items, name = "VECTOR") {
println!(" i is {}; item is {}", i, item);
thread::sleep(Duration::from_millis(1000));
}
}
}
Note that dpi_iter
is a macro for wrapping Vec
items.iter()
into a DumbProgressIndicator
object, which implements Iterator
trait so that it can be used in for construct.
The output will be like
💠 RANGE: 1/3 🌑🌑🌑🌕🌕🌕🌕🌕🌕🌕 💠 VECTOR: 1/3 🌑🌑🌑🌕🌕🌕🌕🌕🌕🌕 💠 … i is 0; item is apple
💠 RANGE: 1/3 🌑🌑🌑🌕🌕🌕🌕🌕🌕🌕 💠 VECTOR: 2/3 🌑🌑🌑🌑🌑🌑🌓🌕🌕🌕 💠 … i is 0; item is banana
💠 RANGE: 1/3 🌑🌑🌑🌕🌕🌕🌕🌕🌕🌕 💠 VECTOR: 3/3 🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑 💠 … i is 0; item is orange
💠 RANGE: 2/3 🌑🌑🌑🌑🌑🌑🌓🌕🌕🌕 💠 VECTOR: 1/3 🌑🌑🌑🌕🌕🌕🌕🌕🌕🌕 💠 … i is 1; item is apple
💠 RANGE: 2/3 🌑🌑🌑🌑🌑🌑🌓🌕🌕🌕 💠 VECTOR: 2/3 🌑🌑🌑🌑🌑🌑🌓🌕🌕🌕 💠 … i is 1; item is banana
💠 RANGE: 2/3 🌑🌑🌑🌑🌑🌑🌓🌕🌕🌕 💠 VECTOR: 3/3 🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑 💠 … i is 1; item is orange
💠 RANGE: 3/3 🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑 💠 VECTOR: 1/3 🌑🌑🌑🌕🌕🌕🌕🌕🌕🌕 💠 … i is 2; item is apple
💠 RANGE: 3/3 🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑 💠 VECTOR: 2/3 🌑🌑🌑🌑🌑🌑🌓🌕🌕🌕 💠 … i is 2; item is banana
💠 RANGE: 3/3 🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑 💠 VECTOR: 3/3 🌑🌑🌑🌑🌑🌑🌑🌑🌑🌑 💠 … i is 2; item is orange
DumbArgParser
use rusty_dumb_tools::prelude::*;
pub fn arg_parser_sample(provide_sample_args: bool) {
let mut parser = DumbArgParser::new();
parser.set_description("This is a simple argument parser.");
dap_arg!("-v", flag2 = "--verbose", fixed = true).add_to(&mut parser); // argument flag "-v" / "--verbose" with fixed value (true) when the flag is present
dap_arg!("-n", flag2 = "--name", default = "nobody").add_to(&mut parser); // argument "-n" / "--name" requiring input value, with default "nobody"
dap_arg!("str-arg").add_to(&mut parser); // positional argument "str-arg" (of type String)
dap_arg!("i32-arg", value = 123).add_to(&mut parser); // positional argument "i32-arg" of type i32 (inferred from the value 123)
dap_arg!("multi-arg").set_multi().add_to(&mut parser); // positional multi-argument "multi-arg" that will accept multiple values (one + rest)
if provide_sample_args {
let in_args: Vec<&str> = vec!["-v", "STR", "888", "m1", "m2", "m3"]; // explicitly provide arguments
parser.process_args(in_args); // parse from command-line arguments
} else {
parser.parse_args(); // parse from command-line arguments
}
println!(". -v: {:?}", parser.get::<bool>("-v"));
println!(". --verbose: {:?}", parser.get::<bool>("--verbose")); // will be the same parameter value as "-v"
println!(". --name: {:?}", parser.get::<String>("--name")); // can use "-n" as well
println!(". str-arg: {:?}", parser.get::<String>("str-arg"));
println!(". i32-arg: {:?}", parser.get::<i32>("i32-arg"));
println!(". multi-arg: {:?}", parser.get_multi::<String>("multi-arg"));
}
If run with provide_sample_args
set to false
, i.e. no arguments provided, output will be like
| !!!
| !!! INVALID INPUT ARGUMENT: argument [str-arg] not provided
| !!!
| USAGE: rusty_dumb_tools [-h] [-v] [-n name] <str-arg> <i32-arg> <multi-arg>
| : This is a simple argument parser.
| . -h, --help : HELP
| . -v, --verbose : FLAG [true]
| . -n name, --name name : OPTIONAL; default [nobody]
| . <str-arg> : REQUIRED; e.g.
| . <i32-arg> : REQUIRED; e.g. 123
| . <multi-arg> ... : REQUIRED; e.g. ...
If run with provide_sample_args
set to true
, output will be like
. -v: Some(true)
. --verbose: Some(true)
. --name: Some("nobody")
. str-arg: Some("STR")
. i32-arg: Some(888)
. multi-arg: Some(["m1", "m2", "m3"])
Next section will present a demo program of using the tools. The sub-demo "selection" is actually implemented using `DumbArgParser` with "sub-selection" for the selected sub-demo like
use rusty_dumb_tools::prelude::*;
pub fn run_demo() {
let mut parser = create_demo_parser();
parser.parse_args();
handle_sub_demo(parser);
}
pub fn create_demo_parser() -> DumbArgParser {
let mut parser = DumbArgParser::new();
parser.set_description("Demos of rusty_dumb_tools.");
dap_arg!("demo", value = "calc")
.set_description("a demo")
.set_with_desc_enums(vec![
"calc:DumbCalcProcessor command-line input demo",
...
])
.set_rest()
.add_to(&mut parser)
.unwrap();
parser
}
pub fn handle_sub_demo(parser: DumbArgParser) {
let demo = match parser.get::
the input demonstrates using `DumbArgParser` for showing "help message"
* `cargo run -- calc -h`
`DumbArgParser` is set up to parse arguments for a sub-command (with another `DumbArgParser` object);
and the above input demonstrates showing of "help message" of the sub-command
* `cargo run -- calc 1.1 + 2.2 * (4.3 - 2.4) + 5`
the above demonstrates how to use a [sub-command] `DumbArgParser` to parse arguments for the sub-command `calc`,
which in turn will show how to use `DumbCalcProcessor` for performing calculation of the sub-command arguments
* `cargo run -- calc-repl`
the above demonstrates how to invoke the sub-command `calc-repl`, which in turn show how `DumbCalcProcessor` like a REPL
* `cargo run -- ltemp Trevor`
the above demonstrates how to use `DumbLineTemplate` to format lines to show data
* `cargo run -- lblscreen`
the above demonstrates how to use `DumbLineByLineScreen` to implement a "progress info panel"
* `cargo run -- arg -f 0.2 5 --string2 VAL1 false 1 2 3`
The output of running `cargo run -- -h`:
```
| USAGE: rusty_dumb_tools [-h] The core for the above DumbJsonProcessor demo is like
use rusty_dumb_tools::prelude::*;
pub fn demo_query_universities(country: &str, show_all: bool) {
let stream = make_connection(&country);
let result = match stream {
Ok(mut stream) => process_connection(&mut stream, show_all),
Err(e) => Err(format!("XXX error: [{}]", e)),
};
match result {
Ok(_) => {}
Err(e) => {
println!("{}", e);
}
}
}
fn make_connection(country: &str) -> Result<TcpStream, Error> {
let mut stream: TcpStream = TcpStream::connect("universities.hipolabs.com:80")?;
let request = format!(
"GET /search?country={} HTTP/1.1\r\nHost: universities.hipolabs.com\r\nAccept: application/json\r\nConnection: close\r\n\r\n",
country.replace(" ", "%20")
);
stream.write_all(request.as_bytes())?;
Ok(stream)
}
fn make_connection_get_response(country: &String) -> Result<String, Error> {
match make_connection(country) {
Ok(mut stream) => {
let mut response = String::new();
stream.read_to_string(&mut response)?;
Ok(response)
}
Err(e) => Err(e),
}
}
fn process_connection(stream: &mut TcpStream, show_all: bool) -> Result<(), String> {
let mut handler = InPlaceJsonEntryHandler::new(move |json_entry| {
let show = show_all || json_entry.field_name == "name";
if show {
println!(
"* `{}` => `{}`",
json_entry.field_name, json_entry.field_value
);
}
});
let mut json_processor = DumbJsonProcessor::new(Box::new(&mut handler));
let mut progress = ProcessJsonProgress::new();
let mut buf = [0; 32];
loop {
match stream.read(&mut buf) {
Ok(size) => {
if size == 0 {
return Ok(());
}
let bytes = &buf[..size];
json_processor.push_json_bytes(bytes, &mut progress);
}
Err(e) => {
return Err(format!("XXX error: [{}]", e));
}
}
}
}
The above DumbLineByLineScreen demo is like</b>
use rusty_dumb_tools::prelude::*;
pub fn demo_lblscreen() {
let mut lbl_demo_screen = {
let mut comps = dlt_comps![
"| ",
dltc!("description", align = 'C').set_truncate_indicator("..."),
" |"
];
let temp1 = DumbLineTemplate::new_fixed_width(40, &comps);
let mut comps = dlt_comps![
"| ",
".".repeat(8),
" |",
dltc!("progress-bar"),
": ",
dltc!("progress%", fixed_width = 4, align = 'R'),
" |"
];
let temp2 = DumbLineTemplate::new_fixed_width(40, &comps);
let settings = LBLScreenSettings {
top_line: Some("-".repeat(40)),
bottom_line: Some("-".repeat(40)),
//screen_height_adjustment: 0,
..LBLScreenSettings::default()
};
DumbLineByLineScreen::new(vec![temp1, temp2], settings)
};
lbl_demo_screen.init();
let mut state = HashMap::<&str, String>::new();
let mut progress_done_percent = 0;
loop {
let progress_percent = format!("{}%", progress_done_percent);
let description = format!("... wait ... loading {} ...", progress_percent);
let progress_bar = ">".repeat(progress_done_percent / 5_usize);
state.insert("description", description);
state.insert("progress-bar", progress_bar);
state.insert("progress%", progress_percent);
lbl_demo_screen.refresh(&state);
thread::sleep(Duration::from_millis(200));
progress_done_percent += 1;
if progress_done_percent > 100 {
break;
}
}
}