I have a hyper
server set up more or less exactly as the third example here: https://docs.rs/hyper/0.14.16/hyper/server/index.html . My version of the handle
function calls some other async
functions, and everything works fine, until I try to encode some URL query params into a string in one of those async functions. My project stops compiling when I include the four lines involving the Serializer
in one of the functions called by handle
:
async fn broken_func(&self, param: &str) -> Result<String, Infallible> {
// ...
let mut s = url::form_urlencoded::Serializer::new(String::new());
// the presence or absence of these two lines has no effect on the bug, but
// they demonstrate how I'm trying to use the Serializer
s.append_pair("key", "value");
println!("{:?}", s.finish());
drop(s); // <-- thought this might help, but it doesn't
// ...
Ok(query_string)
}
The error I get is
generator cannot be sent between threads safely
the trait `std::marker::Sync` is not implemented for `dyn for<'r> std::ops::Fn(&'r str) -> std::borrow::Cow<'_, [u8]>`
I have no idea what this has to do with form_urlencoded::Serializer
. However, I am aware that Serializer
is both !Send
and !Sync
, but in this case I'm only using it within a single function so I don't think that should make a difference? If I remove those four lines above, it goes back to compiling.
So instead, to serialize some key/value pairs into URL query parameters, I have to use the following, which kind of seems ridiculous -- not just because this is needlessly complex for something so simple, but also because url::Url::parse_with_params
uses form_urlencoded::Serializer
under the hood.
let query_string = url::Url::parse_with_params(
"http://example.com",
&[("key", "value")]
)
.unwrap()
.query()
.map(|s| s.to_owned())
.unwrap();
Any idea why trying to explicitly use Serializer
inside an async
function causes things to break?
Caesar hit the nail on the head. The trick of putting s
in a scope fixed it.