I'm trying to call a method that inside in using Tokio to do a request and return the result to my callback.
Since I'm doing it in the main I'm trying to add CondVar to block it until the request is done, but I got next error which I don't knot how to fix:
error[E0434]: can't capture dynamic environment in a fn item
--> src/main.rs:42:34
|
42 | let (lock, cvar) = &*con_var_send;
| ^^^^^^^^^^^^
|
= help: use the `|| { ... }` closure form instead
I tried this:
//for thread sleep
use std::sync::{Arc, Mutex, Condvar};
//My network client
mod swapi;
use swapi::SwapiCallback;
//used in swapi client
#[macro_use]
extern crate lazy_static;
//measure time
use std::time::Instant;
//DTO
use crate::swapi::People;
fn main() {
//barrier
let con_var = Arc::new((Mutex::new(true), Condvar::new()));
let con_var_send = con_var.clone();
//Create callback
struct Callback {
start: Instant,
}
impl Callback {
fn new() -> Callback {
Callback {
start: Instant::now()
}
}
}
unsafe impl Send for Callback {} //require to share it between threads
impl SwapiCallback for Callback {
#[allow(non_snake_case)]
fn onLoad(&self, s: Vec<People>) {
let diff = self.start.elapsed().as_millis();
println!("Request: count {}; duration: {}", s.len(), diff);
//unlock thread
//notify lock that thread finished work
let (lock, cvar) = &*con_var_send;
let mut started = lock.lock().unwrap();
*started = true;
// We notify the condvar that the value has changed.
cvar.notify_one();
}
#[allow(non_snake_case)]
fn onError(&self, s: &str) {
println!("Error: {:#?}", s);
}
}
//call swapi client
let client = swapi::SwapiClient::new();
client.loadAllPeople(Box::new(Callback::new()));
//wait for thread to finish
// Wait for the thread to start up.
let (lock, cvar) = &*con_var;
let mut started = lock.lock().unwrap();
while !*started {
started = cvar.wait(started).unwrap();
}
println!("Main finished")
}
As well I tried to make callback to the struct:
fn main() {
//barrier
let con_var = Arc::new((Mutex::new(true), Condvar::new()));
let con_var_send = con_var.clone();
let unlock = move || {
let (lock, cvar) = &*con_var_send;
let mut started = lock.lock().unwrap();
*started = true;
// We notify the condvar that the value has changed.
cvar.notify_one();
};
//Create callback
struct Callback {
start: Instant,
unlock: Box<dyn FnMut()>,
}
impl Callback {
fn new(unlock: Box<dyn FnMut()>) -> Callback {
Callback {
start: Instant::now(),
unlock: unlock
}
}
}
unsafe impl Send for Callback {} //require to share it between threads
impl SwapiCallback for Callback {
#[allow(non_snake_case)]
fn onLoad(&self, s: Vec<People>) {
let diff = self.start.elapsed().as_millis();
println!("Request: count {}; duration: {}", s.len(), diff);
//unlock thread
//notify lock that thread finished work
(self.unlock)();
}
#[allow(non_snake_case)]
fn onError(&self, s: &str) {
println!("Error: {:#?}", s);
}
}
//call swapi client
let client = swapi::SwapiClient::new();
client.loadAllPeople(Box::new(Callback::new(Box::new(unlock))));
//wait for thread to finish
// Wait for the thread to start up.
let (lock, cvar) = &*con_var;
let mut started = lock.lock().unwrap();
while !*started {
started = cvar.wait(started).unwrap();
}
println!("Main finished")
}
But here I got another error:
error[E0596]: cannot borrow `self.unlock` as mutable, as it is behind a `&` reference
--> src/main.rs:48:13
|
43 | fn onLoad(&self, s: Vec<People>) {
| ----- help: consider changing this to be a mutable reference: `&mut self`
...
48 | (self.unlock)();
| ^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
What is correct way to do it?
If I would had thread::spawn
and move
inside it would work, why it is not ho to handle this with struct?