How can I display help after calling Clap's get_matches? - rust

I'm having the same problem as Is there any straightforward way for Clap to display help when no command is provided?, but the solution proposed in that question is not good enough for me.
.setting(AppSettings::ArgRequiredElseHelp) stops the program if no arguments are provided, and I need the program to carry on execution even if no arguments are provided. I need the help to be displayed in addition.

You could write the string before.
use clap::{App, SubCommand};
use std::str;
fn main() {
let mut app = App::new("myapp")
.version("0.0.1")
.about("My first CLI APP")
.subcommand(SubCommand::with_name("ls").about("List anything"));
let mut help = Vec::new();
app.write_long_help(&mut help).unwrap();
let _ = app.get_matches();
println!("{}", str::from_utf8(&help).unwrap());
}
Or you could use get_matches_safe
use clap::{App, AppSettings, ErrorKind, SubCommand};
fn main() {
let app = App::new("myapp")
.setting(AppSettings::ArgRequiredElseHelp)
.version("0.0.1")
.about("My first CLI APP")
.subcommand(SubCommand::with_name("ls").about("List anything"));
let matches = app.get_matches_safe();
match matches {
Err(e) => {
if e.kind == ErrorKind::MissingArgumentOrSubcommand {
println!("{}", e.message)
}
}
_ => (),
}
}

Related

Rust giving error for Option<usize> when using variable inside of method

I am very new to Rust and decided my first program to be a brainfuck interpreter.
I plan on using jump tables as the solution for the loops.
However I decided to rewrite the method to make it look better (for my tastes) and i got an error that I can't quite understand why
Code before causes no errors:
fn process_jumps(jump_map: &mut Vec<usize>, instructions: &Vec<Inst>){
let mut stack: Vec<usize> = Vec::new();
for (i, inst) in instructions.iter().enumerate() {
match inst {
Inst::LoopOpen => stack.push(i),
Inst::LoopClose => {
jump_map[i] = stack.pop();
jump_map[jump_map[i]] = i;
}
_ => ()
}
}
}
Code after has an error (marked in code):
fn process_jumps(instructions: &Vec<Inst>) -> Vec<usize> {
let mut jump_table: Vec<usize> = Vec::new();
let mut stack: Vec<usize> = Vec::new();
for (i, inst) in instructions.iter().enumerate() {
match inst {
Inst::LoopOpen => stack.push(i),
Inst::LoopClose => {
jump_table[i] = stack.pop(); // expected `usize`, found `Option<usize>`
jump_table[jump_map[i]] = i;
}
_ => ()
}
}
return jump_table;
}
My main question is why my code before didn't need me to check the optional?
Vec's pop() method returns Option<T>, not T.
You need to get the usize value from inside that Option, just make sure you've handled the None case correctly. When you are sure None is not possible, the simplest thing you could do is to unwrap() it.
Neither of your examples should really compile, as they both try to assign Option<usize> to a Vec<usize>.

How to find X in a HashMap of HashMaps?

Given that I know ParentId and ChildId, how would I find the UserId if the hashmap is:
HashMap<ParentId, HashMap<ChildId, HashMap<UserId, Foobar>>>
As my knowledge about Rust is pretty basic, I found that the following works but it's quite verbose, as I don't know any better:
match foobar.get(&pid) {
Some(data1) => {
println!("Found 1: {:?}", data1);
match data1.get(&cid) {
Some(data2) => {
println!("Found 2: {:?}", data2);
...and so on
},
_ => println!("Not found")
}
},
_ => println!("Not found")
}
I've also attempted chained get but it's tricky and did not find how to do it correctly:
foobar
.get(pid)?
.get(cid)?
.get(to_find)
What can I try next?
You can use Option::and_then to chain operations that return Option<_>:
let _: Option<&Foobar> = foobar.get(&pid).and_then(|map| map.get(&cid)).and_then(|map| map.get(&to_find));
Example:
use std::collections::HashMap;
fn main() {
let map: HashMap<i32, HashMap<bool, HashMap<String, bool>>> = HashMap::new();
let _: Option<&bool> = map
.get(&123)
.and_then(|map| map.get(&true))
.and_then(|map| map.get("foo"));
}
Playground
Your try with ? is also correct but it'll only work in a function that returns an Option as it returns None from the function the expression is in if any value is None, which is probably the error you're getting.
fn get(map: &HashMap<i32, HashMap<bool, HashMap<String, bool>>>) -> Option<bool> {
map.get(&123)?.get(&true)?.get("foo").cloned()
}
Edit: As #Jmb pointed out in a comment below, another option is to create and immediately call a closure so you can use the ? operator which could be more readable in certain cases:
let _: Option<&bool> = (|| map.get(&123)?.get(&true)?.get("foo"))();

Rust expected enum `syn::UseTree`, found struct `syn::Path`

I am new to Rust and trying to figure out how to get into a workflow of discovering the structure of this AST returned by syn.
[package]
name = "rust-ast"
version = "0.1.0"
authors = ["Foo Bar <foo#bar.com>"]
edition = "2018"
[dependencies]
syn = { version = "1.0.89", features = ["full", "printing", "visit", "extra-traits"] }
That is the Cargo.toml, and here is the main file:
use syn;
use std::env;
use std::fs::File;
use std::io::Read;
use std::process;
fn main() {
let mut args = env::args();
let _ = args.next(); // executable name
let filename = match (args.next(), args.next()) {
(Some(filename), None) => filename,
_ => {
eprintln!("Usage: dump-syntax path/to/filename.rs");
process::exit(1);
}
};
let mut file = File::open(&filename).expect("Unable to open file");
let mut src = String::new();
file.read_to_string(&mut src).expect("Unable to read file");
let syntax = syn::parse_file(&src).expect("Unable to parse file");
let mut str = String::from("");
for item in syntax.items {
match item {
syn::Item::Use(x) => {
match x.tree {
syn::path::Path { .. } => {
println!("{:#?}", x);
},
}
str.push_str("load");
},
_ => println!("Skip")
}
}
// let iterator = syntax.iter();
// for val in iterator {
// println!("Got: {:#?}", val);
// }
}
I was able to earlier print out the x, which showed:
However, I am getting this error now:
this expression has type `syn::UseTree`
expected enum `syn::UseTree`, found struct `syn::Path`
First of all, how do I discover the API in VSCode? I have enabled the rust plugin so I can click through some definitions, but I look at that terminal output of the AST "types", and then I try to backward figure out what the type is in VSCode. Usually I resort to looking it up on the docs page, but any tips on how to figure out what the API should be would help teach me to fish. But for this particular question, what am I doing wrong? I am simply trying to destructure the AST as much as possible down to the leaves, to get more familiar with Rust (I am just beginning).
But for this particular question, what am I doing wrong?
x.tree is of type UseTree which is an enum:
pub enum UseTree {
Path(UsePath),
Name(UseName),
... other variants snipped ...
}
Therefore you need to match on the Path variant of UseTree:
match x.tree {
UseTree::Path { .. } => { ... },
_ => todo!(),
}
First of all, how do I discover the API in VSCode?
I don't use VS code but I find clicking through works well for Rust and the stdlib and less well for macro heavy libraries such as syn. Fortunately the documentation for syn is really good.
am simply trying to destructure the AST as much as possible down to the leaves, to get more familiar with Rust (I am just beginning).
syn can be quite complex and so I wouldn't advise this as an approach to learning the language.

`while let Ok(t) ... = try_read!(...)` to make neater reading loop

Is it possible to make short, neat loop that will call , as long as result is Ok(x) and act on x ?
E.g. sth like :
use text_io::try_read; // Cargo.toml += text_io = "0.1"
fn main() {
while let Ok(t): Result<i64, _> = try_read!() {
println!("{}", t);
}
}
fails to compile.
If I try to provide type info, then it fails,
when I don't provide , then obviously it's ambiguous how to resolve try_read!.
Here is working - but IMHO way longer - snippet:
use text_io::try_read; // Cargo.toml += text_io = "0.1"
fn main() {
loop {
let mut tok: Result<i64, _> = try_read!();
match tok {
Ok(t) => println!("{}", t),
Err(_) => break,
}
}
}
You can qualify Ok as Result::Ok and then use the "turbofish" operator to provide the concrete type:
fn main() {
while let Result::<i64, _>::Ok(t) = try_read!() {
println!("{}", t);
}
}
(while let Ok::<i64, _>(t) also works, but is perhaps a bit more cryptic.)
Another option is to request the type inside the loop - rustc is smart enough to infer the type for try_read!() from that:
fn main() {
while let Ok(t) = try_read!() {
let t: i64 = t;
println!("{}", t);
}
}
The latter variant is particularly useful in for loops where the pattern match is partly hidden, so there is no place to ascribe the type to.

Is there a way to write a function that using odbc::Statement in a loop?

I have working example of a simple loop (mostly taken from the odbc crate's example):
use std::io;
use odbc::*;
use odbc_safe::AutocommitOn;
fn main(){
let env = create_environment_v3().map_err(|e| e.unwrap()).unwrap();
let conn = env.connect_with_connection_string(CONN_STRING).unwrap();
let mut stmt = Statement::with_parent(&conn).unwrap();
loop {
let mut sql_text = String::new();
println!("Please enter SQL statement string: ");
io::stdin().read_line(&mut sql_text).unwrap();
stmt = match stmt.exec_direct(&sql_text).unwrap() {
Data(mut stmt) => {
let cols = stmt.num_result_cols().unwrap();
while let Some(mut cursor) = stmt.fetch().unwrap() {
for i in 1..(cols + 1) {
match cursor.get_data::<&str>(i as u16).unwrap() {
Some(val) => print!(" {}", val),
None => print!(" NULL"),
}
}
println!();
}
stmt.close_cursor().unwrap()
}
NoData(stmt) => {println!("Query executed, no data returned"); stmt}
}
}
}
I don't want to create new Statements for each query, as I just can .close_cursor().
I'd like to extract the loop's body to a function, like this:
fn exec_stmt(stmt: Statement<Allocated, NoResult, AutocommitOn>) {
//loop's body here
}
But I just can't! The .exec_direct() method mutably consumes my Statement and returns another. I tried different ways to pass Statement arg to the function (borrow, RefCell, etc), but they all fail when using in a loop. I am still new to Rust, so most likely I just don't know something, or does the .exec_direct's Statement consumption makes it impossible?
There's no nice way to move and then move back values through parameters. It's probably best to copy what .exec_direct does and just make the return type of your function a statement as well.
The usage would then look like this:
let mut stmt = Statement::with_parent(&conn).unwrap();
loop {
stmt = exec_stmt(stmnt);
}
and your function signature would be:
fn exec_stmt(stmt: Statement<...>) -> Statement<...> {
match stmt.exec_direct() {
...
}
}
I probably wouldn't recommend this, but if you really wanted to get it to work you could use Option and the .take() method.
fn exec_stmt(some_stmt: &mut Option<Statement<...>>) {
let stmt = some_stmt.take().unwrap();
// do stuff ...
some_stmt.replace(stmt);
}
The odbc-safe crate tried to have each state transition of ODBC reflected in a different type. The odbc-api crate also tries to protect you from errors, but is a bit more subtle about it. Your use case would be covered by the the Preallocated struct.
The analog example from the odbc-api documentation looks like this:
use odbc_api::{Connection, Error};
use std::io::{self, stdin, Read};
fn interactive(conn: &Connection) -> io::Result<()>{
let mut statement = conn.preallocate().unwrap();
let mut query = String::new();
stdin().read_line(&mut query)?;
while !query.is_empty() {
match statement.execute(&query, ()) {
Err(e) => println!("{}", e),
Ok(None) => println!("No results set generated."),
Ok(Some(cursor)) => {
// ...print cursor contents...
},
}
stdin().read_line(&mut query)?;
}
Ok(())
}
This will allow you to declare a function without any trouble:
use odbc_api::Preallocated;
fn exec_statement(stmt: &mut Preallocated) {
// loops body here
}

Resources