How use Rc Refcell in rust (and stdweb) - rust

i have a litle problem with this code:
I have two closure and I want the variable counter to be used in both of them.
fn main() {
stdweb::initialize();
let counter_div = document().query_selector(DIV_SELECTOR_NAME).unwrap().unwrap();
// create Rc RefCell struct here
let mut counter = Rc::new(RefCell::new(ClickCounter::new()));
counter_div.clone().add_event_listener(move |_: MouseDownEvent| {
// ERROR move How make this work?
counter.clone().borrow_mut().increment();
});
let upgrade_div = document().query_selector(UPGRADE_DIV_SELECTOR_NAME).unwrap().unwrap();
upgrade_div.clone().add_event_listener( move |_: MouseDownEvent|{
// ERROR move!
counter.clone().borrow_mut().upgrade_click(upgrade);
});
stdweb::event_loop();
}

When using Rc with move closures, you need to clone first, and then move the variable into the closure. With the code you've written, you're first cloning the variable after it has been moved into the closure, meaning that it is not available when the second closure tries to do the same.
An example:
let counter = Rc::new(RefCell::new(ClickCounter::new()));
{
// Clone into a new variable outside of the closure.
let cloned_counter = counter.clone();
counter_div.add_event_listener(move |_: MouseDownEvent| {
// Note: We're no longer cloning here.
cloned_counter.borrow_mut().increment();
});
}
// ...
{
// Clone the counter variable on line 1 again.
let cloned_counter = counter.clone();
upgrade_div.add_event_listener(move |_: MouseDownEvent| {
cloned_counter.borrow_mut().upgrade_click(upgrade);
});
}

Related

Rust multithread intensive methods which need to access same set of data with Rayon

I use Rayons par_iter()to iterate over different variations of the expensive method I need to run. These runs need to access the same set of checked usizes because they all need to add to it and check it from time to time. I also need them all to shutdown when first thread finishes, this is why I have a kill_switch which will force the iterations to exit when its set to true.
let mut checked: HashSet<usize> = HashSet::new();
let mut kill_switch: bool = false;
permutations.par_iter().for_each(|order| {
let board = Board::new(board_map.clone(), order.clone());
let mut bubbles: Vec<(i8, i8)> = Vec::new();
if let Some(bubbles) = board.solve(&mut bubbles, &mut checked, &kill_switch) {
kill_switch = true;
bubbles.into_iter().for_each(|bubble| {
dbg!(bubble);
});
}
})
This is the code I currently have but I get errors for how I'm using checked and kill_switch. How do I make this work?
Errors:
cannot borrow checked as mutable, as it is a captured variable in a Fn closure
cannot borrow as mutable [E0596]
cannot assign to kill_switch, as it is a captured variable in a Fn closure
cannot assign [E0594]
To fix the errors, you will need to use RefCells to wrap the checked and kill_switch variables and use the borrow_mut method to get a mutable reference to them in the closure.
Here is an example of how you can modify your code:
use std::cell::RefCell;
use std::collections::HashSet;
let checked: RefCell<HashSet<usize>> = RefCell::new(HashSet::new());
let kill_switch: RefCell<bool> = RefCell::new(false);
permutations.par_iter().for_each(|order| {
let board = Board::new(board_map.clone(), order.clone());
let mut bubbles: Vec<(i8, i8)> = Vec::new();
if let Some(bubbles) = board.solve(&mut bubbles, &mut checked.borrow_mut(), &mut kill_switch.borrow_mut()) {
*kill_switch.borrow_mut() = true;
bubbles.into_iter().for_each(|bubble| {
dbg!(bubble);
});
}
})
Note that you will also need to add RefCell as a dependency in your project.

Borrowed value does not live long enough with async funtion

I am new to Rust and trying to make some code async to run a bunch of tasks in parallel. Here is a simplified example:
use futures::future::join_all;
#[tokio::main]
async fn main() {
let mut list = Vec::new();
for i in 1..10 {
let my_str = format!("Value is: {:?}", &i);
let future = do_something(&my_str);
list.push(future);
}
join_all(list).await;
}
async fn do_something(value: &str)
{
println!("value is: {:?}", value);
}
This fails with "Borrowed value does not live long enough" on the do_something(&my_str) call. I can get the code to compile by changing do_something to accept a String instead of an &str. However, it seems a bit strange to require a String when an &str would work. Is there a better pattern to use here? Thanks!
"However, it seems a bit strange to require a String when an &str would work." But an &str can't work here because it only borrows my_str which gets destroyed before the future completes:
for i in 1..10 {
// Create a new `String` and store it in `my_str`
let my_str = format!("Value is: {:?}", &i);
// Create a future that borrows `my_str`. Note that the future is not
// yet started
let future = do_something(&my_str);
// Store the future in `list`
list.push(future);
// Destroy `my_str` since it goes out of scope and wasn't moved.
}
// Run the futures from `list` until they complete. At this point each
// future will try to access the string that they have borrowed, but those
// strings have already been freed!
join_all(list).await;
Instead your do_something should take ownership of the string along with responsibility for freeing it:
use futures::future::join_all;
#[tokio::main]
async fn main() {
let mut list = Vec::new();
for i in 1..10 {
// Create a new `String` and store it in `my_str`
let my_str = format!("Value is: {:?}", &i);
// Create a future and _move_ `my_str` into it.
let future = do_something(my_str);
// Store the future in `list`
list.push(future);
// `my_str` is not destroyed since it was moved into the future.
}
join_all(list).await;
}
async fn do_something(value: String)
{
println!("value is: {:?}", value);
// Destroy `value` since it goes out of scope and wasn't moved.
}

Toggling a bool from within a loop and Fn losure with rust and gtk

I'm trying to make a tic tac toe game with rust and gtk, and in order to swap turns I'm toggling bool when a game button is clicked. Because of the rust/gtk integration, the onclick events run within an Fn closure, so I can't directly edit a mutable reference to the bool.
Based on this post, I moved from a basic bool to a bool within a cell as that has interior mutability, allowing it to be varied from within the closure.
However, the variable gets moved into the closure, and in the next iteration of the loop/usage of xturn I get
--> src/main.rs:45:44
|
39 | let xturn = Cell::new(true);
| ----- move occurs because `xturn` has type `std::cell::Cell<bool>`, which does not implement the `Copy` trait
...
45 | current_button.connect_clicked(move |current_button|{
| ^^^^^^^^^^^^^^^^^^^^^ value moved into closure here, in previous iteration of loop
46 | if current_button.label().unwrap() == ""{
47 | if xturn.get() {
| ----- use occurs due to use in closure
Code below
let game_grid: [[Button; 3];3] = [[new_game_button(), new_game_button(), new_game_button()],[new_game_button(), new_game_button(), new_game_button()],[new_game_button(), new_game_button(), new_game_button()]];
let xturn = Cell::new(true);
for i in 0..3{
for o in 0..3{
let current_button = &game_grid[i][o];
grid.attach(current_button, i.try_into().unwrap(), o.try_into().unwrap(), 1, 1);
current_button.connect_clicked(move |current_button|{
if current_button.label().unwrap() == ""{
if xturn.get() {
current_button.set_label("X");
} else{
current_button.set_label("O");
};
xturn.set(!xturn.get());
} else{
println!("This spot is taken! Go Again.");
}
});
}
}
Creating a reference to each use of xturn by adding & results in the same initial error message
Getting rid of the move at the start of the closure results in this error
error[E0373]: closure may outlive the current function, but it borrows `xturn`, which is owned by the current function
Complete code
use std::cell::Cell;
use gtk4 as gtk;
use gtk::{prelude::*, Label};
use gtk::{Align, Application, ApplicationWindow, Button, Grid};
fn main() {
let app = Application::builder()
.application_id("org.beribus.tictactoe")
.build();
app.connect_activate(build_ui);
println!("Hello, world!");
app.run();
}
fn build_ui(app: &gtk::Application){
let window = ApplicationWindow::builder()
.application(app)
.default_width(360)
.default_height(360)
.title("GTK Tac Toe")
.build();
let grid = Grid::builder()
.margin_top(10)
.margin_bottom(10)
.margin_start(10)
.margin_end(10)
.halign(gtk::Align::Center)
.valign(gtk::Align::Center)
.row_spacing(6)
.column_spacing(6)
.build();
window.set_child(Some(&grid));
let game_grid: [[Button; 3];3] = [[new_game_button(), new_game_button(), new_game_button()],[new_game_button(), new_game_button(), new_game_button()],[new_game_button(), new_game_button(), new_game_button()]];
let xturn = Cell::new(true);
for i in 0..3{
for o in 0..3{
let current_button = &game_grid[i][o];
grid.attach(current_button, i.try_into().unwrap(), o.try_into().unwrap(), 1, 1);
current_button.connect_clicked(move |current_button|{
if current_button.label().unwrap() == ""{
if xturn.get() {
current_button.set_label("X");
} else{
current_button.set_label("O");
};
&xturn.set(!&xturn.get());
} else{
println!("This spot is taken! Go Again.");
}
});
}
}
let text = Label::builder()
.label("woro")
.build();
if xturn.get(){
text.set_label("yoyooyo it's X's turn");
} else{
text.set_label("yoyooyo it's O's turn");
}
grid.attach(&text, 0,4,3,1);
let reset_button = Button::builder()
.halign(Align::Center)
.valign(Align::Center)
.label("Reset Game")
.build();
reset_button.connect_clicked(move |_|{
for i in 0..3{
for o in 0..3{
let current_button = &game_grid[i][o];
current_button.set_label("");
}
}
});
grid.attach(&reset_button, 0,3,3,1);
window.show();
}
fn new_game_button() -> Button{
let button = Button::builder()
.halign(Align::Center)
.valign(Align::Center)
.label("")
.width_request(90)
.height_request(90)
.build();
button
}
Both approaches are flawed, as the compiler indicated.
When you use the move approach, you are telling the closure that it can have xturn, but since this is in a loop, it can execute multiple times. You can't move the same value twice (since it is gone after the first time) and so the second move is disallowed.
When you try to capture by reference, the compiler is telling you that xturn belongs to the function in which it is declared, but the closures you are creating in the loop will outlive the function, and therefore the references will become invalid.
It looks like you want shared ownership of a single bool, which is implemented in Rust by the Rc struct, which performs reference-counting to determine when the shared value can be destroyed.
However, Rc does not permit mutable borrows while more than one Rc exists for the same shared value, so you still need the interior mutability of Cell. The final type that you want to use is Rc<Cell<bool>>. (RefCell isn't required here since you only need to be able to get and set the bool value; you don't ever need a reference to it.)
You need each iteration of the loop to move a copy of the Rc. Each separate Rc value will refer to the same Cell. For example, this function returns 9 closures that all do the same thing: they toggle the shared boolean value and return it in a tuple along with their own index:
fn create_closures() -> Vec<Box<dyn Fn() -> (i32, bool)>> {
let xturn = Rc::new(Cell::new(false));
(0..9).map(|i| -> Box<dyn Fn() -> (i32, bool)> {
// Make a clone of the Rc that this closure can steal.
let xturn = xturn.clone();
Box::new(move || {
let v = !xturn.get();
xturn.set(v);
(i, v)
})
}).collect()
}
(Playground)

Wait for backend thread to finish after application.run in Rust

I want to wait for a backend thread (Like this but in my case the backend manages a database which I want to close properly before the application actually exits) to finish (e.g. join it) after application.run() has finished.
My actual non working main.rs (the closure needs to be non-mut)
the thread to wait for
use gio::prelude::*;
use gtk::prelude::*;
use gtk::{ApplicationWindow, Label};
use std::env::args;
use std::thread;
fn main() {
let application = gtk::Application::new(
Some("com.github.gtk-rs.examples.communication_thread"),
Default::default(),
)
.expect("Initialization failed...");
let (thr, mut receiver) = start_communication_thread();
application.connect_activate(move |application| {
build_ui(application, receiver.take().unwrap())
});
application.run(&args().collect::<Vec<_>>());
thr.join();
}
fn build_ui(application: &gtk::Application, receiver: glib::Receiver<String>) {
let window = ApplicationWindow::new(application);
let label = Label::new(None);
window.add(&label);
spawn_local_handler(label, receiver);
window.show_all();
}
/// Spawn channel receive task on the main event loop.
fn spawn_local_handler(label: gtk::Label, receiver: glib::Receiver<String>) {
receiver.attach(None, move |item| {
label.set_text(&item);
glib::Continue(true)
});
}
/// Spawn separate thread to handle communication.
fn start_communication_thread() -> (thread::JoinHandle<()>, Option<glib::Receiver<String>>) {
let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
let thr = thread::spawn(move || {
let mut counter = 0;
loop {
let data = format!("Counter = {}!", counter);
println!("Thread received data: {}", data);
if sender.send(data).is_err() {
break
}
counter += 1;
thread::sleep(std::time::Duration::from_millis(100));
}
});
(thr, Some(receiver))
}
As mentioned above, the only error remaining is that application.connect_activate() takes an Fn closure, the current implementation is FnMut.
The error message is:
error[E0596]: cannot borrow `receiver` as mutable, as it is a captured variable in a `Fn` closure
--> src/main.rs:17:31
|
17 | build_ui(application, receiver.take().unwrap())
| ^^^^^^^^ cannot borrow as mutable
So you cannot use "receiver" mutably, which is necessary for you to take() its contents.
But if you wrap the receiver inside a Cell, then you can access the immutable Cell's contents mutably. So add this line directly after the line with start_communication_thread():
let receiver = Cell::new(receiver);
There might be some more correct answer as I am only a beginner at Rust, but at least it seems to work.
Please note that this changes the take() call to be called against the Cell instead of Option, whose implementation has the same effect, replacing the Cell's contents with None.

Is there another option to share an Arc in multiple closures besides cloning it before each closure?

I have something like this:
use std::sync::Arc;
fn main() {
let arc = Arc::new(42);
move || { arc.clone() };
move || { arc.clone() };
}
I am getting:
error[E0382]: capture of moved value: `arc`
--> src/main.rs:6:19
|
5 | move || { arc.clone() };
| ------- value moved (into closure) here
6 | move || { arc.clone() };
| ^^^ value captured here after move
|
= note: move occurs because `arc` has type `std::sync::Arc<i32>`, which does not implement the `Copy` trait
I understand why I am getting this: the clone isn't called before arc is passed to the closure. I can fix this by defining each closure in a function and clone the Arc before passing it to the closure, but is there another option?
There is no way around it. You should clone the Arc before it is used in a closure. The common pattern is to re-bind the cloned Arc to the same name in a nested scope:
use std::sync::Arc;
fn main() {
let arc = Arc::new(42);
{
let arc = arc.clone();
move || { /* do something with arc */ };
}
{
let arc = arc.clone();
move || { /* do something else with arc */ };
}
}
This is usually done together with thread::spawn():
use std::sync::{Arc, Mutex};
use std::thread;
const NUM_THREADS: usize = 4;
fn main() {
let arc = Arc::new(Mutex::new(42));
for _ in 0..NUM_THREADS {
let arc = arc.clone();
thread::spawn(move || {
let mut shared_data = arc.lock().unwrap();
*shared_data += 1;
});
}
}
is there another option?
Because this pattern of cloning things before defining a closure is somewhat common, some people have proposed adding something like clone || as an analog to move ||. I wouldn't hold out hope for this happening, but a number of comments there point out that macros can solve the case fairly well.
Several crates provide some form of this macro:
closet
capture
clone_all
It's likely that many projects define their own macro to do something similar. For example, the WASM example rust-todomvc defines:
macro_rules! enclose {
( ($( $x:ident ),*) $y:expr ) => {
{
$(let $x = $x.clone();)*
$y
}
};
}
Which can be used as:
fn main() {
let arc = Arc::new(42);
enclose! { (arc) move || arc };
enclose! { (arc) move || arc };
}

Resources