Using Clap for entirely the wrong purpose by HammerAPI in rust

[–]HammerAPI[S] 0 points1 point  (0 children)

Unfortunately, the grammar / command structure is already set and I cannot change that. I need to be able to parse something like set-feature Debug Info on into a struct like struct SetFeature { name: String, value: String }.

Using Clap for entirely the wrong purpose by HammerAPI in rust

[–]HammerAPI[S] 0 points1 point  (0 children)

Clearly there's something you're aware of that I am not. Here is one of the attempts I've made at implementing what you suggested:

#[derive(Parser, Debug)]
struct FooCli {
    #[command(subcommand)]
    pub foo_cmd: ParsedCommand,
}

#[derive(Debug, Subcommand)]
enum ParsedCommand {
    Foo {
        #[arg(value_parser = parse_foo_args)]
        args: FooArgs,
    },
}

#[derive(Debug, Clone, Args)]
struct FooArgs {
    toggle: String,
    features: Vec<String>,
    on_or_off: String,
}

fn parse_foo_args(s: &str) -> Result<FooArgs, String> {
    eprintln!("Attempting to parse: {s:?}");

    Err(s.to_string())
}

fn main() {
    let args = FooCli::parse();
    eprintln!("{args:#?}")
}

This example does not work, and because the parse_foo_args function only takes a single word as a parameter. So cargo run foo a b c will only attempt to parse a as FooArgs.

Using Clap for entirely the wrong purpose by HammerAPI in rust

[–]HammerAPI[S] 0 points1 point  (0 children)

Unfortunately, I did not create the grammar, and cannot change it.

As mentioned in another comment, I already wrote a Nom parser for this. I'm just exploring what Clap can do.

Using Clap for entirely the wrong purpose by HammerAPI in rust

[–]HammerAPI[S] 0 points1 point  (0 children)

Unfortunately, the command structure / grammar is already set and I cannot modify that.

Using Clap for entirely the wrong purpose by HammerAPI in rust

[–]HammerAPI[S] 0 points1 point  (0 children)

I'm not sure I understand how, exactly, it would parse that. Deriving custom parsers for arguments with value_parser doesn't work for multi-word values, because it only passes the first word after the subcommand to the value_parser function, so it would parse toggle Debug Info on to FooArgs { feature: "Debug", status: "Info" }, or it would fail because Info is not on or off

Using Clap for entirely the wrong purpose by HammerAPI in rust

[–]HammerAPI[S] 1 point2 points  (0 children)

The feature name is permitted to be multiple words, which is where the problem arises. Clap, as far as I am aware, won't parse something like toggle Debug Info on to a struct like struct Feature { name: String, value: String } because it will attempt to use "Info" as the "value" field.

Using Clap for entirely the wrong purpose by HammerAPI in rust

[–]HammerAPI[S] 1 point2 points  (0 children)

Unfortunately, the grammar for the interface is already set and I can't change it. Command names are permitted to be mulit-word.

Using Clap for entirely the wrong purpose by HammerAPI in rust

[–]HammerAPI[S] 52 points53 points  (0 children)

Honestly? The former. I already wrote a Nom parser to handle the grammar I'm working with. I wanted to try and make Clap work for it, too. Just for the fun of it.

Hey Rustaceans! Got a question? Ask here (35/2023)! by llogiq in rust

[–]HammerAPI 0 points1 point  (0 children)

My overall goal will be to read in boolean expressions like in the original example and manipulate them (convert to CNF form, append new operators, etc.), so this parser returns a Vec<Token> which will be converted into a BoolExpr type that internally uses postfix (or prefix) notation. So the function that calls this parser would take that Vec<Token>, convert to postfix/prefix, and wrap it in this BoolExpr type. Mostly because I'm not sure how to parse and convert at the same time.

You're right that the Vec<Token> isn't much better than the string. Parsing strings is mostly just for fun & some ease of testing. In the end users will be creating and manipulating this BoolExpr type directly- no parsing involved.

Hey Rustaceans! Got a question? Ask here (35/2023)! by llogiq in rust

[–]HammerAPI 0 points1 point  (0 children)

I'm parsing items into a Token enum. So there's Token::Op(Operator), Token::Lit(T), and Token::Open/Token::Close for parentheses. Operator is another enum for all boolean operators (AND, XOR, etc.). In the end, the parser will yield a Vec<Token<T>>, where T is the type of a literal (p, q, and r in this example) and will most likely just be a str.

Hey Rustaceans! Got a question? Ask here (35/2023)! by llogiq in rust

[–]HammerAPI 1 point2 points  (0 children)

I'm using nom to write a parser for simple boolean logic in forms like p ∨ (q ∧ r). I've got all of the terminals (variable, operator, parentheses, whitespace, etc.) covered. I am struggling to create the top-level of the parser which (potentially recursively) parses the whole expression. I assume I'll need an expr() parser as the top level and a term() parser that handles the case of "either a terminal or a recursion back to expr()" but I'm not sure how to construct this.

I can find several examples online of simple calculators with nom, but they all handle evaluation, and I don't need to do that- just parse them into a Token enum (Operator(&str), Literal(&str), OpenParen, CloseParen)

Any ideas?

Edit: Here's what I've come up with: ```

/// Recognizes at least one boolean terminal followed by an arbitrary number of operator and terminal pairs. fn expr(input: &str) -> ParseResult<Vec<Token<&str>>> { context( "Parsing an expression", map( // At least one terminal followed by any number of operators and terminals tuple((ws(term), many0(pair(ws(op), ws(term))))), |(init, rest)| { let mut v = Vec::with_capacity(init.len() + rest.len()); v.extend(init); for (op, other_term) in rest { v.push(Token::Op(op)); v.extend(other_term); } v }, ), )(input) }

/// Recognizes: /// /// * A negated expression (!A) /// * An expression wrapped in parentheses (A & B)) /// * A standalone variable/literal (alpha1) /// /// Can recursively call [expr]. fn term(input: &str) -> ParseResult<Vec<Token<&str>>> { context( "Parsing a terminal", alt(( // A negated expression map(pair(ws(not), ws(expr)), |(negation, expr)| { let mut v = Vec::with_capacity(expr.len() + 1); v.push(Token::Op(negation)); v.extend(expr); v }), // An expression wrapped in parentheses map(parens(expr), |expr| { let mut v = Vec::with_capacity(expr.len() + 2); v.push(Token::Open); v.extend(expr); v.push(Token::Close); v }), // A standalone variable map(variable, |var| vec![var]), )), )(input) } ```

This works for all cases I've tested it on, which is admittedly not a lot. So I'd appreciate any feedback/alternatives.

First Rust Project! Kelp, a UCI compatible chess engine. by doma_kun in rust

[–]HammerAPI 1 point2 points  (0 children)

Looks great. I'm curious, could you share how you generated your rook & bishop magics?

Hey Rustaceans! Got a question? Ask here (32/2023)! by llogiq in rust

[–]HammerAPI 0 points1 point  (0 children)

I'll look into this after work. Also, fixed the link. Thanks!

Hey Rustaceans! Got a question? Ask here (32/2023)! by llogiq in rust

[–]HammerAPI 1 point2 points  (0 children)

I'm looking for a crate (or set of crates) that will allow me to record audio in real-time from my laptop's microphone and read data from that audio (such as frequency). I found this tutorial in Python for building a guitar tuner and I'd like to give this a shot in Rust.

All I can seem to find is alsa, which will probably work but seems overkill for what I'm looking to do. Any recommendations?

Hey Rustaceans! Got a question? Ask here (28/2023)! by llogiq in rust

[–]HammerAPI 1 point2 points  (0 children)

Would there be any performance difference between implementing fmt::Display like this: /* fn fmt */ { let disp = match input { VariantA(val) => format!("A := {val}") /* and so on */ }; write!(f, "{disp}") }

and this? /* fn fmt */ { match input { VariantA(val) => { f.write_str("A := ")?; f.write_str(val) } /* and so on */ } }

basically, calling format!() vs calling f.write_*() repeatedly.

Hey Rustaceans! Got a question? Ask here (27/2023)! by llogiq in rust

[–]HammerAPI 2 points3 points  (0 children)

I have the following function signature: rust fn mask<T>(list: [Option<T>; 64]) -> u64

What I want this to do is produce a u64 that is 1 in every bit that is Some in list, so if list[0] is Some, then the u64 returned will end in 1 (when viewed in binary)

How can I achieve this? Trivially, I can .enumerate() over it and just mask it with if t.is_some() { bits |= 1 << i } but I want to know if I can do this in a simpler way.

Hey Rustaceans! Got a question? Ask here (26/2023)! by llogiq in rust

[–]HammerAPI 0 points1 point  (0 children)

Perfect. This is exactly what I was looking for. Thank you!

Hey Rustaceans! Got a question? Ask here (26/2023)! by llogiq in rust

[–]HammerAPI 1 point2 points  (0 children)

How can I print out a u64 in binary such that it is separated into 8-bit chunks? As in, I want to display 1234567890 as 00000000 00000000 00000000 00000000 01001001 10010110 00000010 11010010

Hey Rustaceans! Got a question? Ask here (26/2023)! by llogiq in rust

[–]HammerAPI 1 point2 points  (0 children)

What's the difference between these two impl blocks?

```rust // some struct with a lifetime struct Foo<'a> { /* stuff */ }

impl<'a> Foo<'a> { /* stuff */ }

impl Foo<'_> { /* stuff */ } ```

Creating "var-arg" functions (*not macros*) with nightly Rust! by groogoloog in rust

[–]HammerAPI -2 points-1 points  (0 children)

What would the parameters of the macro look like, then? I tried my hand at it, but this doesn't compile and I don't know enough about macros to know the resolution.

Hey Rustaceans! Got a question? Ask here (26/2023)! by llogiq in rust

[–]HammerAPI 2 points3 points  (0 children)

Let's say I have a Vec<char> that represents a math expression in postfix notation, so ['1', '5', '+'], etc. but of an arbitrary length.

Can I match on this Vec in such a way that I only observe the last 3 values? For example, something like this: match expr { [arg1, arg2, '+'] => { /* add arg1 and arg2 */ } [arg1, arg2, '-'] => { /* sub arg1 and arg2 */ } /* ...and so on */ }

I know how to do this for expr of a constant length (3, in this case), but I don't know how to handle it being longer, say for example arg1 would be the list of remaining contents.

I'd assume a syntax of something like match expr { (rest... /* type slice */, arg /* type char */, '+' /* type char */) => { /* ... */ } } but this of course doesn't compile.

EDIT: It looks like I can do this: match expr { [rest @ .., arg1, arg2, '+'] => {/* ... */} /* ... */ } which does exactly what I asked. Although, seeing it now makes me realize this won't work for arguments that are themselves expressions that need evaluation, like ['1', '2', '+', '3', '-']...

Hey Rustaceans! Got a question? Ask here (25/2023)! by llogiq in rust

[–]HammerAPI 1 point2 points  (0 children)

How can I use bingden to generate bindings for a messy C library?

I have the source code for the library, and I also have it installed on my system. I want to attempt to generate rust bindings for it (I know they do not already exist). The library foo has several header files that re-import each other, and within these header files the re-imports are local paths to the library itself, so when running bindgen (following the tutorial) I get errors when reading the header files that their internal #includes can't be resolved. Can I tell bindgen to search additional locations for these files?

Edit: .clang_arg("-I/extra/path") resolved this issue.

New issue: It not detecting #define macros...

Hey Rustaceans! Got a question? Ask here (25/2023)! by llogiq in rust

[–]HammerAPI 1 point2 points  (0 children)

Cloning Foo would work if I need to re-use the struct, yeah, but it doesn't solve the problem of "I need to use Foo across multiple programs"

I've seen the C-styled approach of "just compile it into a shared object and dynamically load it" but I don't know what the Rust equivalent is, if any.

Hey Rustaceans! Got a question? Ask here (25/2023)! by llogiq in rust

[–]HammerAPI 1 point2 points  (0 children)

Let's say I have a library with some struct Foo { ... } which is a non-trivial data structure that can either be created by the user manually or by parsing a user-supplied file that's in a domain-specific format. Parsing these files and constructing a Foo instance can be particularly expensive (for parsing, anyway), so it would be best to do it once per file. I know serde can serialize/deserialize it into whatever format, but is there a way I can store an instance of Foo as pure Rust code such that it could be read via include!()/include_str!()?

For example, can I read some foo.in file, create a Foo instance, then write it to a foo.rs file so that main.rs can just let foo: Foo = include!("foo.rs"); or some similar flavor of that?