Nested closure borrow failed - rust

I want to parse a YAML file and use the value inside a service for a HTTP request. Line 35 is the end of main function.
extern crate hyper;
extern crate libc;
extern crate yaml_rust;
use hyper::rt::Future;
use hyper::service::service_fn_ok;
use hyper::{Body, Response, Server};
use std::sync::Arc;
use yaml_rust::YamlLoader;
fn main() {
let content: String = String::from("response: Hello world");
let cfg = Arc::new(YamlLoader::load_from_str(content.as_str()).unwrap());
let cfg0 = (&cfg[0]).clone();
let cfg_response = (&cfg0)["response"].as_str().unwrap();
// A `Service` is needed for every connection, so this
// creates on of our `hello_world` function.
let handle = move || {
let cfg_response = cfg_response.clone();
service_fn_ok(move |_| Response::new(Body::from(String::from(cfg_response.clone()))))
};
// Serve HTTP protocol
// This is our socket address...
let addr: std::net::SocketAddr = ([127, 0, 0, 1], 3000).into();
let server = Server::bind(&addr)
.serve(handle)
.map_err(|e| eprintln!("server error: {}", e));
// Run this server for... forever!
hyper::rt::run(server);
}
Unfortunately, I encountered a nested closure leading to a strange borrow error:
error[E0597]: `cfg0` does not live long enough
--> src/main.rs:15:26
|
15 | let cfg_response = (&cfg0)["response"].as_str().unwrap();
| ^^^^ borrowed value does not live long enough
...
35 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
I tried to
clone it before borrow
use Arc to make it counter-based,
modify assignment
all to no avail
Why does this happen? How do I solve this?

The functions you pass the closure into - hyper::server::Builder::serve and hyper::rt::run() - require their arguments to be 'static, rather than being bounded by any function. main isn't considered special in this regard.
The value bounding it, cfg_response, is captured by the outer closure, so the nested closure isn't necessary to get the error.
Here's a very small program that has the same problem:
fn main() {
let cfg0 = String::from("hello world");
let cfg_response: &str = &cfg0;
let handle = move || {
// this closure takes ownership of cfg_response, a reference to cfg0. Since cfg0 will not
// outlive the function, neither can handle. If it instead took ownership of cfg0 or a
// clone of it, it would have no outside references and could live forever.
return cfg_response.to_owned();
};
serve(handle);
}
fn serve<F: Fn() -> String + 'static>(handle: F) {
loop {
println!("{}", handle());
}
}
As #Stargateur pointed out, this can be solved by making cfg_response owned.
Alternatively, you could initialize cfg0 in a lazy_static like so:
#[macro_use]
extern crate lazy_static;
lazy_static! {
static ref cfg0: String = String::from("hello world");
}
This way, you can still use a borrowed value because it meets the lifetime requirements.

Related

How to set the value of a struct inside a GTK event in rust?

How to set the value of a struct inside a GTK event in rust?
I'm gettting an error when trying to modify the s struct instance below.
use gtk::prelude::*;
use gio::prelude::*;
use gtk::{Application, ApplicationWindow, Button};
struct SomeStruct {
val: bool,
}
fn main() {
let mut s = SomeStruct {
val: false,
};
application.connect_activate(|app| {
let window = ApplicationWindow::new(app);
window.set_title("test");
window.set_default_size(350,70);
let button = Button::with_label("Test");
button.connect_clicked(|_|{
s.val = true; // error here
});
window.add(&button);
window.show_all();
});
application.run(&[]);
}
Error messages:
error[E0597]: `s` does not live long enough
error[E0596]: cannot borrow `s` as mutable, as it is a captured variable in a `Fn` closure
Your code has two issues:
Although s outlives the GTK application, Rust doesn't know that, whis is why it complains of s not living long enough.
ButtonExt::connect_clicked() accepts a Fn, so it's not allowed to mutate data without extra precautions.
The first issue can be fixed by allocating s on the heap and accessing it through a reference-counted pointer, which ensures that the object lives at least as long as the closure that refers to it.
The second issue is easiest to resolve through interior mutability, by wrapping SomeStruct into a RefCell. RefCell holds a value and allows the holder to mutate it through a shared reference to the RefCell. When requesting a mut reference to the inner value, RefCell will check at run-time that no other reference to the value is still live. (This could happen if your closure were to get access to the value and then, while holding the value, called another closure that does the same.)
Those two combined would lead to code like this (untested):
use std::rc::Rc;
use std::cell::RefCell;
fn main() {
let s = Rc::new(RefCell::new(SomeStruct { val: false }));
application.connect_activate(|app| {
let window = ApplicationWindow::new(app);
window.set_title("test");
window.set_default_size(350, 70);
let button = Button::with_label("Test");
// clone the handle to s and move it into the closure
let s2 = Rc::clone(&s);
button.connect_clicked(move |_| {
s2.borrow_mut().val = true;
});
window.add(&button);
window.show_all();
});
application.run(&[]);
}

Return a reference to a T inside a lazy static RwLock<Option<T>>?

I have a lazy static struct that I want to be able to set to some random value in the beginning of the execution of the program, and then get later. This little silly snippet can be used as an example:
use lazy_static::lazy_static;
use std::sync::RwLock;
struct Answer(i8);
lazy_static! {
static ref ANSWER: RwLock<Option<Answer>> = RwLock::new(None);
}
fn answer_question() {
*ANSWER.write().unwrap() = Some(Answer(42));
}
fn what_is_the_answer() -> &'static Answer {
ANSWER
.read()
.unwrap()
.as_ref()
.unwrap()
}
This code fails to compile:
error[E0515]: cannot return value referencing temporary value
--> src/lib.rs:15:5
|
15 | ANSWER
| _____^
| |_____|
| ||
16 | || .read()
17 | || .unwrap()
| ||_________________- temporary value created here
18 | | .as_ref()
19 | | .unwrap()
| |__________________^ returns a value referencing data owned by the current function
I know you can not return a reference to a temporary value. But I want to return a reference to ANSWER which is static - the very opposite of temporary! I guess it is the RwLockReadGuard that the first call to unwrap returns that is the problem?
I can get the code to compile by changing the return type:
fn what_is_the_answer() -> RwLockReadGuard<'static, Option<Answer>> {
ANSWER
.read()
.unwrap()
}
But now the calling code becomes very unergonomic - I have to do two extra calls to get to the actual value:
what_is_the_answer().as_ref().unwrap()
Can I somehow return a reference to the static ANSWER from this function? Can I get it to return a RwLockReadGuard<&Answer> maybe by mapping somehow?
once_cell is designed for this: use .set(...).unwrap() in answer_question and .get().unwrap() in what_is_the_answer.
As far as I understand your intention, the value of Answer can't be computed while it is being initialized in the lazy_static but depends on parameters known only when answer_question is called. The following may not be the most elegant solution, yet it allows for having a &'static-reference to a value that depends on parameters only known at runtime.
The basic approach is to use two lazy_static-values, one of which serves as a "proxy" to do the necessary synchronization, the other being the value itself. This avoids having to access multiple layers of locks and unwrapping of Option-values whenever you access ANSWER.
The ANSWER-value is initialized by waiting on a CondVar, which will signal when the value has been computed. The value is then placed in the lazy_static and from then on unmovable. Hence &'static is possible (see get_the_answer()). I have chosen String as the example-type. Notice that accessing ANSWER without calling generate_the_answer() will cause the initialization to wait forever, deadlocking the program.
use std::{sync, thread};
lazy_static::lazy_static! {
// A proxy to synchronize when the value is generated
static ref ANSWER_PROXY: (sync::Mutex<Option<String>>, sync::Condvar) = {
(sync::Mutex::new(None), sync::Condvar::new())
};
// The actual value, which is initialized from the proxy and stays in place
// forever, hence allowing &'static access
static ref ANSWER: String = {
let (lock, cvar) = &*ANSWER_PROXY;
let mut answer = lock.lock().unwrap();
loop {
// As long as the proxy is None, the answer has not been generated
match answer.take() {
None => answer = cvar.wait(answer).unwrap(),
Some(answer) => return answer,
}
}
};
}
// Generate the answer and place it in the proxy. The `param` is just here
// to demonstrate we can move owned values into the proxy
fn generate_the_answer(param: String) {
// We don't need a thread here, yet we can
thread::spawn(move || {
println!("Generating the answer...");
let mut s = String::from("Hello, ");
s.push_str(&param);
thread::sleep(std::time::Duration::from_secs(1));
let (lock, cvar) = &*ANSWER_PROXY;
*lock.lock().unwrap() = Some(s);
cvar.notify_one();
println!("Answer generated.");
});
}
// Nothing to see here, except that we have a &'static reference to the answer
fn get_the_answer() -> &'static str {
println!("Asking for the answer...");
&ANSWER
}
fn main() {
println!("Hello, world!");
// Accessing `ANSWER` without generating it will deadlock!
//get_the_answer();
generate_the_answer(String::from("John!"));
println!("The answer is \"{}\"", get_the_answer());
// The second time a value is generated, noone is listening.
// This is the flipside of `ANSWER` being a &'static
generate_the_answer(String::from("Peter!"));
println!("The answer is still \"{}\"", get_the_answer());
}

nom parser borrow checker issue

I have this Rust program using nom 4.2.2. (I have taken the liberty of expanding the nom parser function.)
extern crate failure;
extern crate nom;
use failure::Error;
use std::fs::File;
use std::io::Read;
fn nom_parser(i: &[u8]) -> ::nom::IResult<&[u8], String, u32> {
{ ::nom::lib::std::result::Result::Ok((i, ("foo".to_owned()))) }
}
fn my_parser(buf: &[u8]) -> Result<(&[u8], String), Error> {
Ok((buf, "foo".to_owned()))
}
fn main() -> Result<(), Error> {
let handler = |mut entries: String| { entries.clear() };
loop {
let mut buf = Vec::new();
File::open("/etc/hosts")?.read_to_end(&mut buf)?;
let res = nom_parser(&buf)?.1;
// let res = my_parser(&buf)?.1;
handler(res);
}
}
Compiling this program with rustc 1.33.0 (2aa4c46cf 2019-02-28) yields the following issue:
error[E0597]: `buf` does not live long enough
--> nom-parsing/src/main.rs:21:26
|
21 | let res = nom_parser(&buf)?.1;
| -----------^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `buf` is borrowed for `'static`
...
24 | }
| - `buf` dropped here while still borrowed
Switching to the commented out version of the parser compiles just fine. How are my_parser and nom_parser different? Who is borrowing buf? How should I change the program to placate the borrow checker?
let res = nom_parser(&buf)?.1;
^ here
You are using the ? operator to propagate the error out of main. The IResult<&[u8], String, u32> = Result<(&[u8], String), nom::Err<&[u8], u32>>. So in case of error the &buf is returned as part of it, so it must stay alive even after main function exits, but it won't because buf is local variable inside main.
In your case the nom_parser never returns error, but the validation only cares about the types and function signatures.
To fix it, you should process the error somehow before propagating it up. For example:
let res = nom_parser(&buf).map_err(|_| failure::format_err!("Parsing failed!"))?.1;
Note that Err in the IResult is not always hard error. It could be nom::Err::Incomplete, meaning that the parsing may succeed if more data is supplied, or nom::Err::Error meaning that the input was not matched by the parser (so perhaps another parser in alt! could succeed), or nom::Err::Failure, meaning that something went really wrong during parsing. Depending on the situation, you may consider them all as failure, or handle them differently.
The problem appears to be in IResult<I, O, E = u32>, which expends to Result<(I, O), Err<I, E>>
As you can see, when you use the ?, the Err that you may return can still contain a reference to the type I, which is your &[u8], and return from your function.
The only way for the function to return this reference would be that the reference has a lifetime that doesn't end with the function, 'static
A simple solution to your problem would be to change the &[u8] to a Vec<u8>, even if I'm not sure what you're trying to do with it.

tokio-curl: capture output into a local `Vec` - may outlive borrowed value

I do not know Rust well enough to understand lifetimes and closures yet...
Trying to collect the downloaded data into a vector using tokio-curl:
extern crate curl;
extern crate futures;
extern crate tokio_core;
extern crate tokio_curl;
use std::io::{self, Write};
use std::str;
use curl::easy::Easy;
use tokio_core::reactor::Core;
use tokio_curl::Session;
fn main() {
// Create an event loop that we'll run on, as well as an HTTP `Session`
// which we'll be routing all requests through.
let mut lp = Core::new().unwrap();
let mut out = Vec::new();
let session = Session::new(lp.handle());
// Prepare the HTTP request to be sent.
let mut req = Easy::new();
req.get(true).unwrap();
req.url("https://www.rust-lang.org").unwrap();
req.write_function(|data| {
out.extend_from_slice(data);
io::stdout().write_all(data).unwrap();
Ok(data.len())
})
.unwrap();
// Once we've got our session, issue an HTTP request to download the
// rust-lang home page
let request = session.perform(req);
// Execute the request, and print the response code as well as the error
// that happened (if any).
let mut req = lp.run(request).unwrap();
println!("{:?}", req.response_code());
println!("out: {}", str::from_utf8(&out).unwrap());
}
Produces an error:
error[E0373]: closure may outlive the current function, but it borrows `out`, which is owned by the current function
--> src/main.rs:25:24
|
25 | req.write_function(|data| {
| ^^^^^^ may outlive borrowed value `out`
26 | out.extend_from_slice(data);
| --- `out` is borrowed here
|
help: to force the closure to take ownership of `out` (and any other referenced variables), use the `move` keyword, as shown:
| req.write_function(move |data| {
Investigating further, I see that Easy::write_function requires the 'static lifetime, but the example of how to collect output from the curl-rust docs uses Transfer::write_function instead:
use curl::easy::Easy;
let mut data = Vec::new();
let mut handle = Easy::new();
handle.url("https://www.rust-lang.org/").unwrap();
{
let mut transfer = handle.transfer();
transfer.write_function(|new_data| {
data.extend_from_slice(new_data);
Ok(new_data.len())
}).unwrap();
transfer.perform().unwrap();
}
println!("{:?}", data);
The Transfer::write_function does not require the 'static lifetime:
impl<'easy, 'data> Transfer<'easy, 'data> {
/// Same as `Easy::write_function`, just takes a non `'static` lifetime
/// corresponding to the lifetime of this transfer.
pub fn write_function<F>(&mut self, f: F) -> Result<(), Error>
where F: FnMut(&[u8]) -> Result<usize, WriteError> + 'data
{
...
But I can't use a Transfer instance on tokio-curl's Session::perform because it requires the Easy type:
pub fn perform(&self, handle: Easy) -> Perform {
transfer.easy is a private field that is directly passed to session.perform.
It this an issue with tokio-curl? Maybe it should mark the transfer.easy field as public or implement new function like perform_transfer? Is there another way to collect output using tokio-curl per transfer?
The first thing you have to understand when using the futures library is that you don't have any control over what thread the code is going to run on.
In addition, the documentation for curl's Easy::write_function says:
Note that the lifetime bound on this function is 'static, but that is often too restrictive. To use stack data consider calling the transfer method and then using write_function to configure a callback that can reference stack-local data.
The most straight-forward solution is to use some type of locking primitive to ensure that only one thread at a time may have access to the vector. You also have to share ownership of the vector between the main thread and the closure:
use std::sync::Mutex;
use std::sync::Arc;
let out = Arc::new(Mutex::new(Vec::new()));
let out_closure = out.clone();
// ...
req.write_function(move |data| {
let mut out = out_closure.lock().expect("Unable to lock output");
// ...
}).expect("Cannot set writing function");
// ...
let out = out.lock().expect("Unable to lock output");
println!("out: {}", str::from_utf8(&out).expect("Data was not UTF-8"));
Unfortunately, the tokio-curl library does not currently support using the Transfer type that would allow for stack-based data.

captured variable does not outlive the enclosing closure [duplicate]

This question already has an answer here:
Lifetime troubles sharing references between threads
(1 answer)
Closed 7 years ago.
I have a threading operation in Rust which requires the use of a variable passed as an argument to the function the threads are spawned within, however I am seeing the following compile time error:
Compiling Test v0.0.1 (file:///Users/clarkj84/Desktop/RustTest)
main.rs:9:22: 9:35 error: captured variable `test` does not outlive the enclosing closure
main.rs:9 let handle = thread::spawn(move || {
^~~~~~~~~~~~~
main.rs:7:20: 16:2 note: captured variable is valid for the anonymous lifetime #1 defined on the block at 7:19
main.rs:7 fn test(test: &str){
main.rs:8 for _x in 0..2 {
main.rs:9 let handle = thread::spawn(move || {
main.rs:10 for _y in 0..2 {
main.rs:11 println!("{}", test);
main.rs:12 }
...
note: closure is valid for the static lifetime
error: aborting due to previous error
Could not compile `Test`.
To learn more, run the command again with --verbose.
This is my code implementation:
use std::thread;
fn main() {
test("test");
}
fn test(test: &str){
for _x in 0..2 {
let handle = thread::spawn(move || {
for _y in 0..2 {
println!("{}", test);
}
});
}
}
Checkout #Shepmaster's answer for an explanation. There are two solutions to your problem depending on your use-case.
If your use case is just string literals (of type &'static str) and not arbitrary strings that are created during the program's execution, you can modify your function's signature to
fn test(test: &'static str)
This will allow you to pass any string literal to this function and move the string literal to another thread.
If on the other hand you want to create new strings by e.g. taking them from program arguments or environment variables, then you can create one String object per thread and pass that.
use std::thread;
use std::env;
fn main() {
test("test");
test(std::env::var("HOME").unwrap()); // pass the current home-directory
}
fn test(test: &str) {
for _x in 0..2 {
let string_object = test.to_string();
let handle = thread::spawn(move || {
for _y in 0..2 {
println!("{}", string_object);
}
});
}
}

Resources