I have rockets code to return JSON pretty or compact based on the query param "pretty". Don't care about the value of "pretty", just needs to be present. i.e request could be api?pretty=1, api?pretty=true or simply api?pretty
32 | let json_stringer = match req.get_query_value("pretty") {
| ^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated function `get_query_value`
The type is irrelevant to the handler code. The match clause Some(_) doesn't care about the param's type!
Is this a deliberate limitation of Rust (with good reason) I should learn, or a language bug I should chase up on?
Thanks
The problem is the compiler still needs to know what type it would have, otherwise it doesn't know which version of get_query_value() to call or how much stack space to set aside for the return value.
Thank you, this helps me understand it better!
However, if we can see that the inner value from Option<T> is never accessed at compile-time or run-time, then (as the rust compiler) we could select the smallest/fastest version of get_query_value() to be called here, I think?
Another reason for the OP is that Rust is statically typed; if it can't figure out the type of a value, that's always an error.
Even if the compiler had some metric for smallest/fastest codes, the methods may have side-effects and other impacts. For example, your method drops a String now. And it's just not good to have the compiler arbitrarily choose something in the face of ambiguity, as it becomes impossible to know what the compiler will do. This would especially hurt if you, the programmer, thought there was only a single possibility, but there were multiple, and the compiler silently picked one you didn't expect.
A logical reason it matters in this case is that which values of the parameter will result in a Some or Nonevaries based on the type. At a guess you may want &RawStr (but I didn't check edge cases; maybe you'll need your own type). If the compiler arbitrarily chose u8 or bool, probably only a small set of values would do what you seem to desire.
I would expect, for example, that req.get_query_value::<i32>("pretty") would fail if someone passed ?pretty=yes. So even if you aren't consuming it, that doesn't mean the function you're calling doesn't care.
(Also, please pick a different API. ?pretty=no giving pretty output is very confusing.)
Thanks @quinedot this extends my knowledge further.
Agreed in my case &RawStr is the logical type param - I don't want the framework to parse a value for the param, just give it to me raw.
I still think my problem is quite ubiquitous and begs a neat solution: rephrased it is
Let me test a function returning Option<T>, has returned Some(_). I am really checking for presence on a thing with "get" methods and unfortunately no "has" methods.
If the language doesn't support that now, could there be an acceptable spec for writing a default function version returning Option<_> - for a caller who doesn't care about the inner value?
Thanks, ?pretty=no would cause a surprising result with this logic.
How would you design it? I guess the simple way is to require ?pretty=1 and reject anything else.
The problem is, whether the function returns a Some(_) or a None could depend on what T is (e.g., if the function calls a trait method on T to decide). So the compiler has no way to resolve an Option<T> method with a generic "Option<_>".
As a side note, it is possible to directly check the existence of a query parameter without parsing it:
That's usually called if blah.get("a").is_some(), which works great on things like a HashMap. But the fact that .parse().is_ok() doesn't work is good because there's no general way to ask "does this parse?" without saying into what you're trying to parse it.
This method exists only to be used by manual routing. To retrieve query values from a request, use Rocket’s code generation facilities.
So it's probably fine that it doesn't support what you're trying to do tidily.
And note that it returns Option<Result<T, T::Error>>, so Some(_) is arguably an anti-pattern on it, as it allows ignoring an error without saying what you're ignoring.
The way I generally do APIs (albeit not in Rust) is to accept basically an Option<bool> in those situations. That way:
? and ?pretty and ?pretty= are all "just use the default", so that people can generate query strings conveniently.
?pretty=true and ?pretty=false are supported for setting it
?pretty=1 and ?pretty=if-the-moon-is-full are HTTP 400 Bad Request errors.
I'm trying be cleverer than the standard Rockets pattern for parameters; I don't want every request handler function to be aware of ?pretty. The handler will return my JSON struct and then as it gets converted to a Response, we check the request params to decide if the JSON text should be pretty or not. More DRY.
In the end I went with this, I'm not sure if it can be made cleaner...
let json_stringer = match req.get_query_value::<bool>("pretty") {
Some(val) => match val {
Ok(true) => serde_json::to_string_pretty,
_ => serde_json::to_string,
},
None => serde_json::to_string,
};