From Axum Example: https://github.com/tokio-rs/axum/examples/query-params-with-empty-strings/src/main.rs#L23-L25
async fn handler(Query(params): Query<Params>) -> String {
format!("{:?}", params)
}
What is the name of the signature pattern when Query(params) is used on param left?
What is the name of the signature pattern when Query(params) is used on param left?
It's literally just a pattern (as in pattern-matching): in Rust, a binding (a parameter, or the left-hand side of a let, or the left hand side of a for) can be a pattern as long as it's infallible (/ irrefutable*). match and friends are necessary for refutable patterns (patterns which can fail, because they only match a subset of all possible values).
Some languages call this destructuring but Rust doesn't make a difference.
For Axum, it's just a convenient way of accessing the contents of the query parameter (or other extractors), you could also write this as:
async fn handler(query: Query<Params>) -> String {
format!("{:?}", query.0)
}
or
async fn handler(query: Query<Params>) -> String {
let Query(params) = query;
format!("{:?}", params)
}
Related
I'm about to return a string depending the given argument.
fn hello_world(name:Option<String>) -> String {
if Some(name) {
return String::formatted("Hello, World {}", name);
}
}
This is a not available associated function! - I wanted to make clear what I want to do. I browsed the doc already but couldn't find any string builder functions or something like that.
Use the format! macro:
fn hello_world(name: Option<&str>) -> String {
match name {
Some(n) => format!("Hello, World {n}"),
None => format!("Who are you?"),
}
}
In Rust, formatting strings uses the macro system because the format arguments are typechecked at compile time, which is implemented through a procedural macro.
There are other issues with your code:
You don't specify what to do for a None - you can't just "fail" to return a value.
The syntax for if is incorrect, you want if let to pattern match.
Stylistically, you want to use implicit returns when it's at the end of the block.
In many (but not all) cases, you want to accept a &str instead of a String.
See also:
Is there a way to pass named arguments to format macros without repeating the variable names?
Since Rust 1.58 it's possible to use named parameters, too.
fn hello_world(name: Option<&str>) -> String {
match name {
Some(n) => format!("Hello, World {n}"),
None => format!("Who are you?"),
}
}
I have a function like this
fn get_html(address: &str) -> String {
let mut response = reqwest::blocking::get(
address,
);
response = response.unwrap_or_else(|_e| {String::from("")});
response = response.text().unwrap_or_else(|_e| {String::from("")});
return response
}
Where I'm checking for html content. I would like to return an empty String if any kind of an error occurs somewhere in this function.
I'm not sure how to deal with this because unwrap_or_else expecting Result not String.
The reqwest::blocking::get() function is returning a Result<Response>.
To obtain the html, you have to unwrap this result and call .text() method.
That will return a Result<String>, that you have to unwrap again.
In your code you assign a String::from("") when you unwrap the Result<Response>, and that is not right, because you have a Response when it is Ok and a String when it is an Err.
Instead you should match the result and return the String from the function:
fn get_html(address: &str) -> String {
let mut response = reqwest::blocking::get(
address,
);
match response {
Ok(response) => response.text().unwrap_or_else(|_e| String::from("")),
Err(_) => String::from(""),
}
}
In this code, you use unwrap_or_else() just on the .text() result.
While if you have an error on the response itself, you return a String from the function.
An idiomatic way to solve your issue would be to refactor slightly your code: because code in get_html could fail, it's natural that its signature reflects this, so instead of returning a String, it could return an Option<String>, leaving the caller decide on what to do in this case:
fn get_html(address: &str) -> Option<String> {
reqwest::blocking::get(address)
.ok()?
.text()
.ok()
}
See the playground.
This makes the code much more straightforward. However, you may really want the signature of the function to be -> String, not -> Option<String>. In this case, there are two solutions.
The first solution would be to use the experimental try block. I mention this solution, not because it's currently the most adequate, but because it will be one day (most likely).
fn get_html(address: &str) -> String {
let result: Option<_> = try {
reqwest::blocking::get(address)
.ok()?
.text()
.ok()?
};
result.unwrap_or_default()
}
See the playground.
Note that, as is, Rust is not able to figure out types on its own for the try block, so we have to help it, which makes this more verbose. This aspect will probably improve over time, when try blocks are stabilized.
Also note that, since the Default::default constructor of String produces an empty string, we can directly use .unwrap_or_default() instead of .unwrap_or(String::new()) or .unwrap_or_else(|| String::new()) (since an empty string is not allocated, the first option is also acceptable).
The second solution would simply be to add an other function with the wanted signature, and make it use the first function
fn get_html_failable(address: &str) -> Option<String> {
reqwest::blocking::get(address)
.ok()?
.text()
.ok()
}
fn get_html(address: &str) -> String {
get_html_failable(address).unwrap_or_default()
}
This may seem unconvenient, but lots of libraries in Rust have internal error propagation using types that represent failure (such as Result or Option), because it's really convenient to write such functions and to compose them (both reqwest::blocking::get and .text() return a Result, and see how easy it is to use them in a function that returns an Option), and have wrapper function that expose the wanted signature (most libraries will still expose fail types, but if you are writing an application it's not necessarily the best choice).
A variable of both preceding workarounds is to "simulate" a try block in stable Rust, without relying on an additional toplevel function.
fn get_html(address: &str) -> String {
(|| reqwest::blocking::get(address).ok()?.text().ok())()
.unwrap_or_default()
}
See the playground.
Note that, in this case, countrary to the try version, Rust is able to figure out the right types on its own.
This is probably the least readable solution, so I wouldn't recommend it (use try blocks instead). But it works.
I'm about to return a string depending the given argument.
fn hello_world(name:Option<String>) -> String {
if Some(name) {
return String::formatted("Hello, World {}", name);
}
}
This is a not available associated function! - I wanted to make clear what I want to do. I browsed the doc already but couldn't find any string builder functions or something like that.
Use the format! macro:
fn hello_world(name: Option<&str>) -> String {
match name {
Some(n) => format!("Hello, World {n}"),
None => format!("Who are you?"),
}
}
In Rust, formatting strings uses the macro system because the format arguments are typechecked at compile time, which is implemented through a procedural macro.
There are other issues with your code:
You don't specify what to do for a None - you can't just "fail" to return a value.
The syntax for if is incorrect, you want if let to pattern match.
Stylistically, you want to use implicit returns when it's at the end of the block.
In many (but not all) cases, you want to accept a &str instead of a String.
See also:
Is there a way to pass named arguments to format macros without repeating the variable names?
Since Rust 1.58 it's possible to use named parameters, too.
fn hello_world(name: Option<&str>) -> String {
match name {
Some(n) => format!("Hello, World {n}"),
None => format!("Who are you?"),
}
}
I'm trying to create a macro that generates two functions from a function signature. As the signature of the functions is dependent from what is passed to the macro, the number of function arguments is varying.
The functions I want to create are (i) an internal function, that actually does something (which I was able to generate as I wanted) and (ii) a public function that should wrap around the internal function. The function signatures are the same regarding the parameters. Therefore, it should be easy to pass all the arguments that were passed to the public function down into the internal function.
The following snippet shows the simplified macro generation for the public function. How can I achieve that the arguments are passed down correctly? (#params_from_public_function)
let public_function_ident = ...;
let internal_function_ident = ...;
// ast_function_stub-Type: ForeignItemFn
let params_from_public_function: Punctuated<FnArg, Comma> = ast_function_stub.sig.inputs.clone();
quote! {
pub fn #public_name(#params_from_public_function) {
#internal_function_ident(#params_from_public_function);
}
}
Here are two examples, how the resulting macro should work:
generate_both_functions!(fn foo(someParam: &str) -> u8;);
// What the macro should generate:
fn _foo(someParam: &str) -> u8 { // Internal function
// Some internal stuff happens here
}
pub fn foo(someParam: &str) { // Public function
_foo(someParam);
}
// Second example (having two instead of one argument and different types)
generate_both_functions!(fn bar(param1: i32, param2: String) -> String;);
// What the macro should generate
fn _bar(param1: i32, param2: String) -> String {
// Internal stuff again
}
fn bar(param1: i32, param2: String) {
_bar(param1, param2);
}
Just to clarify: I was able to correctly parse the macro's input (generate_both_functions!) and extract the function argument metadata from the AST. However, I am not able to pass the actual inputs dynamically to the internal function.
This is not possible in full generality. Consider the following function signature, which makes use of destructuring in argument position to extract the fields of its first parameter:
fn bar(Foo { a, b, .. }: Foo)
Since the Foo has been destructured, there is no way for the macro to generate code which passes it to another function with the exact same signature. You might try to reconstruct the Foo and call _bar like _bar(Foo { a, b }), but due to the .. some of the fields have been permanently lost and it cannot be reconstructed.
The only remaining option here is to extract the set of bindings from the pattern (which is not trivial), and generate a function that takes each of those bindings as separate parameters. But this is also impossible. We'd have to generate a signature like fn _bar(a: A, b: B), where A and B are the types of a and b. But the macro cannot see the declaration of the type Foo, and so it has no way to determine what these types are.
Alternatives
It is possible to support the common case where each argument has the form $ident: $type. All you need to do in this case is to check that the pat field on each syn::FnArg is a Pat::Ident and grab the name of the argument. Then you can generate a matching signature for _bar and pass each argument in.
If no external code needs to call _bar, you can make it a by-move closure:
fn bar(/* any signature you like */) {
let _bar = move || { /* body goes here, using any arguments from bar */ };
_bar();
}
This should inherit all the bindings of the outer function
seamlessly, but the outer function will no longer be able to use them
after, which may be a dealbreaker.
First of all: Thank you #AlphaModder!
As I don't want to support the destructuring case, i went with your first alternative. I want to explain how I finally achieved what I want, so that people with similar issues are able to fix it faster than me.
First of all, I constructed the function itself using the ItemFn-Struct instead of using the parse_quote!-Macro:
// The idents from both functions
let internal_function_ident = ...;
let public_function_ident = ...;
// The arguments with the following pattern: $ident: $type, $ident: $type, ...
let params_from_public_function: Punctuated<FnArg, Comma> = ast_function_stub.sig.inputs.clone();
// Transform the arguments to the pattern: $ident, $ident, ...
let transformed_params = transform_params(params_from_public_function.clone());
// Assemble the function
ItemFn {
...
sig: syn::Signature {
...
ident: public_function_ident,
inputs: params_from_public_function
},
block: parse_quote!({
#internal_function_ident#transformed_params;
})
}
The transform_params-function then looks like this:
fn transform_params(params: Punctuated<syn::FnArg, syn::token::Comma>) -> Expr {
// 1. Filter the params, so that only typed arguments remain
// 2. Extract the ident (in case the pattern type is ident)
let idents = params.iter().filter_map(|param|{
if let syn::FnArg::Typed(pat_type) = param {
if let syn::Pat::Ident(pat_ident) = *pat_type.pat.clone() {
return Some(pat_ident.ident)
}
}
None
});
// Add all idents to a Punctuated => param1, param2, ...
let mut punctuated: Punctuated<syn::Ident, Comma> = Punctuated::new();
idents.for_each(|ident| punctuated.push(ident));
// Generate expression from Punctuated (and wrap with parentheses)
let transformed_params = parse_quote!((#punctuated));
transformed_params
}
I am implementing a function-like procedural macro which takes a single string literal as an argument, but I don't know how to get the value of the string literal.
If I print the variable, it shows a bunch of fields, which includes both the type and the value. They are clearly there, somewhere. How do I get them?
extern crate proc_macro;
use proc_macro::{TokenStream,TokenTree};
#[proc_macro]
pub fn my_macro(input: TokenStream) -> TokenStream {
let input: Vec<TokenTree> = input.into_iter().collect();
let literal = match &input.get(0) {
Some(TokenTree::Literal(literal)) => literal,
_ => panic!()
};
// can't do anything with "literal"
// println!("{:?}", literal.lit.symbol); says "unknown field"
format!("{:?}", format!("{:?}", literal)).parse().unwrap()
}
#![feature(proc_macro_hygiene)]
extern crate macros;
fn main() {
let value = macros::my_macro!("hahaha");
println!("it is {}", value);
// prints "it is Literal { lit: Lit { kind: Str, symbol: "hahaha", suffix: None }, span: Span { lo: BytePos(100), hi: BytePos(108), ctxt: #0 } }"
}
After running into the same problem countless times already, I finally wrote a library to help with this: litrs on crates.io. It compiles faster than syn and lets you inspect your literals.
use std::convert::TryFrom;
use litrs::StringLit;
use proc_macro::TokenStream;
use quote::quote;
#[proc_macro]
pub fn my_macro(input: TokenStream) -> TokenStream {
let input = input.into_iter().collect::<Vec<_>>();
if input.len() != 1 {
let msg = format!("expected exactly one input token, got {}", input.len());
return quote! { compile_error!(#msg) }.into();
}
let string_lit = match StringLit::try_from(&input[0]) {
// Error if the token is not a string literal
Err(e) => return e.to_compile_error(),
Ok(lit) => lit,
};
// `StringLit::value` returns the actual string value represented by the
// literal. Quotes are removed and escape sequences replaced with the
// corresponding value.
let v = string_lit.value();
// TODO: implement your logic here
}
See the documentation of litrs for more information.
To obtain more information about a literal, litrs uses the Display impl of Literal to obtain a string representation (as it would be written in source code) and then parses that string. For example, if the string starts with 0x one knows it has to be an integer literal, if it starts with r#" one knows it is a raw string literal. The crate syn does exactly the same.
Of course, it seems a bit wasteful to write and run a second parser given that rustc already parsed the literal. Yes, that's unfortunate and having a better API in proc_literal would be preferable. But right now, I think litrs (or syn if you are using syn anyway) are the best solutions.
(PS: I'm usually not a fan of promoting one's own libraries on Stack Overflow, but I am very familiar with the problem OP is having and I very much think litrs is the best tool for the job right now.)
If you're writing procedural macros, I'd recommend that you look into using the crates syn (for parsing) and quote (for code generation) instead of using proc-macro directly, since those are generally easier to deal with.
In this case, you can use syn::parse_macro_input to parse a token stream into any syntatic element of Rust (such as literals, expressions, functions), and will also take care of error messages in case parsing fails.
You can use LitStr to represent a string literal, if that's exactly what you need. The .value() function will give you a String with the contents of that literal.
You can use quote::quote to generate the output of the macro, and use # to insert the contents of a variable into the generated code.
use proc_macro::TokenStream;
use syn::{parse_macro_input, LitStr};
use quote::quote;
#[proc_macro]
pub fn my_macro(input: TokenStream) -> TokenStream {
// macro input must be `LitStr`, which is a string literal.
// if not, a relevant error message will be generated.
let input = parse_macro_input!(input as LitStr);
// get value of the string literal.
let str_value = input.value();
// do something with value...
let str_value = str_value.to_uppercase();
// generate code, include `str_value` variable (automatically encodes
// `String` as a string literal in the generated code)
(quote!{
#str_value
}).into()
}
I always want a string literal, so I found this solution that is good enough. Literal implements ToString, which I can then use with .parse().
#[proc_macro]
pub fn my_macro(input: TokenStream) -> TokenStream {
let input: Vec<TokenTree> = input.into_iter().collect();
let value = match &input.get(0) {
Some(TokenTree::Literal(literal)) => literal.to_string(),
_ => panic!()
};
let str_value: String = value.parse().unwrap();
// do whatever
format!("{:?}", str_value).parse().unwrap()
}
I had similar problem for parsing doc attribute. It is also represented as a TokenStream. This is not exact answer but maybe will guide in a proper direction:
fn from(value: &Vec<Attribute>) -> Vec<String> {
let mut lines = Vec::new();
for attr in value {
if !attr.path.is_ident("doc") {
continue;
}
if let Ok(Meta::NameValue(nv)) = attr.parse_meta() {
if let Lit::Str(lit) = nv.lit {
lines.push(lit.value());
}
}
}
lines
}