I am new to threads in Rust. I am struggling to pass the RustBox type from the rustbox crate within threads.
I want to press the q key and have it display a + symbol for 2 secs at (1, 1) while I press w key within those 2 secs which shows another + symbol at (1, 2).
I wrote some code for the same logic:
extern crate rustbox;
use std::thread;
use std::time::Duration;
use rustbox::{Color, RustBox};
use rustbox::Key;
fn mark_at(x: usize, y: usize, rustbox: &RustBox) {
rustbox.print(x, y, rustbox::RB_BOLD, Color::Black, Color::White, "+");
thread::spawn(move || {
let delay = Duration::from_millis(2000);
thread::sleep(delay);
rustbox.print(x, y, rustbox::RB_BOLD, Color::Black, Color::White, " ");
});
}
fn main() {
let rustbox = match RustBox::init(Default::default()) {
Result::Ok(v) => v,
Result::Err(e) => panic!("{}", e),
};
rustbox.print(1, 1, rustbox::RB_BOLD, Color::Black, Color::White, " ");
rustbox.print(1, 2, rustbox::RB_BOLD, Color::Black, Color::White, " ");
loop {
rustbox.present();
match rustbox.poll_event(false) {
Ok(rustbox::Event::KeyEvent(key)) => {
match key {
Key::Char('q') => {
mark_at(1, 1, &rustbox);
}
Key::Char('w') => {
mark_at(1, 2, &rustbox);
}
Key::Esc => { break; }
_ => { }
}
},
Err(e) => panic!("{}", e),
_ => { }
}
}
}
It gives me:
error[E0277]: the trait bound `*mut (): std::marker::Sync` is not satisfied in `rustbox::RustBox`
--> src/main.rs:12:5
|
12 | thread::spawn(move || {
| ^^^^^^^^^^^^^ `*mut ()` cannot be shared between threads safely
|
= help: within `rustbox::RustBox`, the trait `std::marker::Sync` is not implemented for `*mut ()`
= note: required because it appears within the type `std::marker::PhantomData<*mut ()>`
= note: required because it appears within the type `rustbox::RustBox`
= note: required because of the requirements on the impl of `std::marker::Send` for `&rustbox::RustBox`
= note: required because it appears within the type `[closure#src/main.rs:12:19: 16:6 rustbox:&rustbox::RustBox, x:usize, y:usize]`
= note: required by `std::thread::spawn`
error: aborting due to previous error
How do I implement Sync for the RustBox type so that above code could work?
RustBox doesn't implement Send, so there is no (safe) way to share it between threads (it seems you already found the not yet merged pull request https://github.com/gchp/rustbox/pull/65 which would support Send).
If the pull request gets merged you could wrap the RustBox in a Mutex, i.e. Mutex<RustBox>, and references to that can be shared between threads.
But then you'll hit lifetime issues: your rustbox reference doesn't live long enough to spawn a new thread using it, so you'll have to wrap it in Arc.
use std::sync::{Arc,Mutex};
fn mark_at(x: usize, y: usize, rustbox: &Arc<Mutex<RustBox>>) {
rustbox.lock().unwrap().print(x, y, rustbox::RB_BOLD, Color::Black, Color::White, "+");
let rustbox = rustbox.clone(); // increment reference counter
thread::spawn(move || {
let delay = Duration::from_millis(2000);
thread::sleep(delay);
rustbox.lock().unwrap().print(x, y, rustbox::RB_BOLD, Color::Black, Color::White, " ");
});
}
In your main function you'll have to wrap the rustbox:
let rustbox = Arc::new(Mutex::new(rustbox));
and lock() it every time you use it.
Make sure you don't keep the lock too long; it might help to use helper variables to make this more explicit, e.g:
let pe = rustbox.lock().unwrap().poll_event(false);
match pe {
// ...
}
Related
This question already has answers here:
How to use take_while with futures::Stream?
(2 answers)
Closed 3 years ago.
I want to run an event loop in one thread and handle data from a UDP socket until another thread signals to stop work.
This is a difficult task for me, so I want to start from a simpler task:
one thread starting the event loop and waiting for another thread to signal the end:
use futures::{future, future::Future, stream::Stream, sync::mpsc};
use std::{io, io::BufRead, thread};
fn main() {
let (mut tx, rx) = mpsc::channel::<bool>(1);
let thr = thread::spawn(|| {
let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap();
runtime.spawn(
future::lazy(|| {
println!("event loop started");
Ok(())
})
.and_then(rx.take_while(|x| *x == true).into_future()),
);
runtime.run()
});
let stdin = io::stdin();
for line in stdin.lock().lines() {
let line = line.unwrap();
println!("{}", line);
if line == "exit" {
tx.try_send(false).unwrap();
break;
}
}
thr.join().unwrap().unwrap();
}
This code doesn't compile:
error[E0277]: the trait bound `bool: futures::future::Future` is not satisfied
--> src/main.rs:14:26
|
14 | .and_then(rx.take_while(|x| *x == true).into_future()),
| ^^^^^^^^^^ the trait `futures::future::Future` is not implemented for `bool`
|
= note: required because of the requirements on the impl of `futures::future::IntoFuture` for `bool`
error[E0599]: no method named `into_future` found for type `futures::stream::take_while::TakeWhile<futures::sync::mpsc::Receiver<bool>, [closure#src/main.rs:14:37: 14:51], bool>` in the current scope
--> src/main.rs:14:53
|
14 | .and_then(rx.take_while(|x| *x == true).into_future()),
| ^^^^^^^^^^^
|
= note: the method `into_future` exists but the following trait bounds were not satisfied:
`futures::stream::take_while::TakeWhile<futures::sync::mpsc::Receiver<bool>, [closure#src/main.rs:14:37: 14:51], bool> : futures::stream::Stream`
`&mut futures::stream::take_while::TakeWhile<futures::sync::mpsc::Receiver<bool>, [closure#src/main.rs:14:37: 14:51], bool> : futures::stream::Stream`
How do I fix the compilation error?
Read and understand the documentation and function signature of methods you attempt to use:
fn take_while<P, R>(self, pred: P) -> TakeWhile<Self, P, R>
where
P: FnMut(&Self::Item) -> R,
R: IntoFuture<Item = bool, Error = Self::Error>,
Self: Sized,
take_while takes a closure that returns some type that must be convertible into a future; a bool is not convertible into a future. The simplest way to do this is via future::ok:
let thr = thread::spawn(|| {
let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap();
runtime.spawn({
rx.take_while(|&x| future::ok(x))
.for_each(|x| {
println!("{}", x);
future::ok(())
})
});
runtime.run()
});
See also:
The trait bound `(): futures::Future` is not satisfied when using TcpConnectionNew
But my problem also in joining future::lazy and rx.take_while
That's an unrelated problem to what you asked about. Again, we look at the docs, this time for Future::and_then:
fn and_then<F, B>(self, f: F) -> AndThen<Self, B, F>
where
F: FnOnce(Self::Item) -> B,
B: IntoFuture<Error = Self::Error>,
Self: Sized,
Similarly to take_while, it takes a closure and the closure must return something that can be convertible into a future. Your code doesn't provide a closure.
Then look at Stream::into_future. This returns a type that implements Future and returns a tuple. The first item in the tuple is a single value from the stream, the second is the stream itself, to allow getting more values.
To get all the item and error types correct, I've make liberal use of map(drop) and map_err(drop) — you will want to do something better for your data and error handling.
runtime.spawn({
future::lazy(|| {
println!("event loop started");
Ok(())
})
.and_then(|_| {
rx.take_while(|&x| future::ok(x))
.into_future()
.map(drop)
.map_err(drop)
})
.map(drop)
});
Really, you should just use a oneshot channel; it's much simpler:
use futures::{
future::{self, Future},
sync::oneshot,
};
use std::thread;
fn main() {
let (tx, rx) = oneshot::channel();
let thr = thread::spawn(|| {
let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap();
runtime.spawn({
future::lazy(|| {
println!("event loop started");
Ok(())
})
.and_then(|_| rx.map_err(drop))
});
runtime.run()
});
let lines = ["hello", "goodbye", "exit"];
for &line in &lines {
if line == "exit" {
tx.send(()).unwrap();
break;
}
}
thr.join().unwrap().unwrap();
}
When using a match to modify a mutable variable, I haven't found a way to use match in a way that is guaranteed to be non-exhaustive and not requiring clone.
struct Stuff {
num: u32,
thing: bool,
}
enum Bar {
Nothing,
SomeStuff(Stuff),
AlsoNothing,
}
fn main() {
let mut things = vec![Bar::SomeStuff(Stuff {
num: 2,
thing: false,
})];
for x in things.iter_mut() {
*x = match *x {
Bar::Nothing => Bar::AlsoNothing,
Bar::AlsoNothing => Bar::SomeStuff(Stuff {
num: 3,
thing: true,
}),
Bar::SomeStuff(thing) => panic!("not sure"),
}
}
}
error[E0507]: cannot move out of borrowed content
--> src/main.rs:19:20
|
19 | *x = match *x {
| ^^ cannot move out of borrowed content
...
25 | Bar::SomeStuff(thing) => panic!("not sure"),
| ----- hint: to prevent move, use `ref thing` or `ref mut thing`
My intent is to write Bar::SomeStuff(thing) => Bar::SomeStuff(thing) and effectively leave it unchanged, but I cannot move through with a borrow or a reference.
Bar::SomeStuff(thing.clone()) could work, but copying a big struct could be very expensive.
Removing the *x = and changing to () could also work, but I am only returning a Bar enum so having the compiler check the return type is something I hope to keep.
If you want to pass a value unchanged, just capture the match with a variable and pass that back, e.g.
fn foo(a: u32) -> u32 {
match a {
0 => 1,
1 => 2,
e => e,
}
}
In your case, I would move the variable assignment into the match arms
for x in things.iter_mut() {
match x {
Bar::Nothing => *x = Bar::AlsoNothing,
Bar::AlsoNothing => *x = Bar::SomeStuff(Stuff { num: 3, thing: true }),
_ => {},
}
}
I've never understood why I have received the Rust error "cannot move out of borrowed content".
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
use std::vec::Vec;
pub struct user_type {
pub name: String,
pub ilist: Vec<i32>,
pub user_type_list: VecDeque<Option<Rc<RefCell<user_type>>>>,
pub parent: Option<Rc<RefCell<user_type>>>,
}
impl user_type {
pub fn new(name: String) -> Self {
user_type {
name: name.clone(),
ilist: Vec::new(),
user_type_list: VecDeque::new(),
parent: Option::None,
}
}
pub fn to_string(&self) -> String {
let mut result: String = String::new();
result += "name is ";
result += &self.name;
let n = self.user_type_list.len();
for iter in &self.user_type_list {
match iter {
Some(ref x) => {
let temp = x.into_inner();
let temp2 = temp.to_string();
result += &temp2[..];
}
None => panic!("to_string"),
}
result += "\n";
}
result
}
}
The full error message is:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:34:32
|
34 | let temp = x.into_inner();
| ^ cannot move out of borrowed content
What is the origin of this kind of error?
Look carefully at this code:
for iter in &self.user_type_list {
match iter {
Some(ref x) => {
let temp = x.into_inner();
let temp2 = temp.to_string();
result += &temp2[..];
}
None => panic!("to_string"),
}
result += "\n";
}
Here, you are iterating &self.user_type_list so the type of iter is actually a reference to the contained value: &Option<Rc<RefCell<user_type>>>. That is nice, because you do not want to take ownership of the container or its values.
Then you match iter to Some(ref x). Older compiler versions would fail because you are matching a reference to a non-reference, but new compilers will do as if you are matching a Option<&T> instead of a &Option<T>, if needed. That is handy, and means that you can write just Some(x) => and x will be of type &Rc<RefCell<user_type>> instead of &&Rc<..> (not that it really matters, automatic dereferencing will make those equivalent).
Now you are calling x.into_inner() with a &Rc<RefCell<..>> and that will never work. It looks like you want to get the RefCell into temp that is not needed, Rc implements Deref so you get that for free. Instead the compiler thinks you are calling RefCell::into_inner(self) -> T, but this function consumes the self to get to the contained value. And you do not own it, you just borrowed it. That is what the error message means: you are trying to consume (move out) and object you do not own (borrowd).
What you really want is just to borrow the user_type enough to call to_string():
Some(x) => {
let temp = x.borrow().to_string();
result += &temp;
}
I am writing a Phoenix client library for Rust, taking advantage of the async websocket client from rust-websockets. Right now I am having trouble figuring out how to pass callback functions into the thread that is handling the websocket traffic. I have a simplified struct:
pub struct Socket {
endpoint: String,
connected: Arc<AtomicBool>,
state_change_close: Option<Box<FnMut(String)>>,
}
This struct has a connect function laid out as follows:
pub fn connect(&mut self) -> Result<(), String> {
if self.connected.load(Ordering::Relaxed) {
return Ok(())
}
// Copy endpoint string, otherwise we get an error on thread::spawn
let connection_string = self.endpoint.clone();
let (usr_msg, stdin_ch) = mpsc::channel(0);
let connection_thread = thread::spawn(move || {
// tokio core for running event loop
let mut core = Core::new().unwrap();
let runner = ClientBuilder::new(&connection_string)
.unwrap()
.add_protocol("rust-websocket")
.async_connect_insecure(&core.handle())
.and_then(|(duplex, _)| {
let (sink, stream) = duplex.split();
stream.filter_map(|message| {
println!("Received Message: {:?}", message);
match message {
OwnedMessage::Close(e) => {
// This is the line where I am trying to call the callback
if let Some(ref mut func) = self.state_change_close {
(func)(e.unwrap().reason);
}
Some(OwnedMessage::Close(e))
},
_ => None,
}
})
.select(stdin_ch.map_err(|_| WebSocketError::NoDataAvailable))
.forward(sink)
});
// Start the event loop
core.run(runner).unwrap();
});
self.connected.store(true, Ordering::Relaxed);
return Ok(())
}
When I try to compile this code I get the following error:
error[E0277]: the trait bound `std::ops::FnMut(std::string::String) + 'static: std::marker::Send` is not satisfied
--> src\socket.rs:99:29
|
99 | let connection_thread = thread::spawn(move || {
| ^^^^^^^^^^^^^ the trait `std::marker::Send` is not implemented for `std::ops::FnMut(std::string::String) + 'static`
|
I have tried changing the type of state_change_close to a Mutex<Option<...>> to avoid thread safety issues, but that did not help with this problem. Is what I'm trying to do possible?
After doing some more research I realized that I just had to modify Option<Box<FnMut(String)>> to be Option<Box<FnMut(String) + Send>> and copy that around my code to everywhere that the callback might be set. Learning more about trait objects!
This code looks like it would work fine to me, but the rust borrow checker doesn't like it:
extern crate rustbox;
use std::error::Error;
use std::default::Default;
use rustbox::{Color, RustBox};
use rustbox::Key;
use std::fs::File;
use std::env;
use std::io::BufReader;
use std::io::BufRead;
fn display_screenful(rb: &RustBox, fr: BufReader<&'static File>, offset: usize) {
for (rline, idx) in fr.lines().zip(0..).skip(offset).take(rb.height()) {
match rline {
Ok(line) => (*rb).print(0, idx, rustbox::RB_NORMAL, Color::White, Color::Black, &line),
Err(_) => (*rb).print(0, idx, rustbox::RB_NORMAL, Color::White, Color::Black, "")
}
}
}
fn main() {
let rustbox = match RustBox::init(Default::default()) {
Ok(v) => v,
Err(e) => panic!(e),
};
let path = env::args().nth(1).unwrap();
let file = match File::open(&path) {
Ok(file) => file,
Err(e) => panic!(e)
};
let file_reader = BufReader::new(&file);
display_screenful(&rustbox, file_reader, 0);
rustbox.present();
loop {
match rustbox.poll_event(false) {
Ok(rustbox::Event::KeyEvent(key)) => {
match key {
Some(Key::Char('q')) => { break; }
Some(Key::Char(' ')) => {
display_screenful(&rustbox, file_reader, rustbox.height());
rustbox.present();
}
_ => { }
}
},
Err(e) => panic!("{}", e.description()),
_ => { }
}
}
}
I guess I could not use a separate function, and use two for loop parts, instead, but that isn't idiomatic Rust, nor is it good coding practice. In fact, I've tried that, but it just tells me that I'm using a moved value. Here are some errors that I'm getting:
Compiling rusted v0.1.0 (file:///Users/christopherdumas/rusted)
src/main.rs:34:39: 34:43 error: `file` does not live long enough
src/main.rs:34 let file_reader = BufReader::new(&file);
^~~~
note: reference must be valid for the static lifetime...
src/main.rs:33:7: 55:2 note: ...but borrowed value is only valid for the block suffix following statement 2 at 33:6
src/main.rs:33 };
src/main.rs:34 let file_reader = BufReader::new(&file);
src/main.rs:35
src/main.rs:36 display_screenful(&rustbox, file_reader, 0);
src/main.rs:37 rustbox.present();
src/main.rs:38
...
src/main.rs:45:53: 45:64 error: use of moved value: `file_reader` [E0382]
src/main.rs:45 display_screenful(&rustbox, file_reader, rustbox.height());
^~~~~~~~~~~
src/main.rs:45:53: 45:64 help: run `rustc --explain E0382` to see a detailed explanation
src/main.rs:36:33: 36:44 note: `file_reader` moved here because it has type `std::io::buffered::BufReader<&'static std::fs::File>`, which is non-copyable
src/main.rs:36 display_screenful(&rustbox, file_reader, 0);
^~~~~~~~~~~
error: aborting due to 2 previous errors
Could not compile `rusted`.
To learn more, run the command again with --verbose.
Firstly, you shouldn't ask for a BufReader<&'static File>. You can't provide one. Ask instead for a BufReader<&'a File> for some lifetime 'a.
fn display_screenful<'a>(rb: &RustBox, fr: BufReader<&'a File>, offset: usize)
or, for short,
fn display_screenful(rb: &RustBox, fr: BufReader<&File>, offset: usize)
That's not enough either - you then end up moving file_reader into the function. You should borrow instead:
fn display_screenful(rb: &RustBox, fr: &mut BufReader<&File>, offset: usize)
and then it compiles.