Is there a simple way to move clone of Rc into closure? - rust

I need to move a clone of Rc value into several closures. Is there a better way to do it rather than cloning it before every closure?
let val = Rc::new(my_val);
let val_clone = val.clone();
closure_func1(move || { do_stuff1(val_clone) });
let val_clone = val.clone();
closure_func2(move || { do_stuff2(val_clone) });
let val_clone = val.clone();
closure_func3(move || { do_stuff3(val_clone) });

You could create a utility function to remove the repetition:
fn with_cloned<T>(rc: &Rc<T>, f: impl FnOnce(Rc<T>)) -> impl FnOnce() {
let rc = Rc::clone(rc);
move || f(rc)
}
let val = Rc::new(my_val);
closure_func1(with_cloned(&val, |val_clone| do_stuff1(val_clone)));
closure_func2(with_cloned(&val, |val_clone| do_stuff2(val_clone)));
closure_func3(with_cloned(&val, |val_clone| do_stuff3(val_clone)));

I found this little macro in the comments under this issue:
macro_rules! enclose {
( ($( $x:ident ),*) $y:expr ) => {
{
$(let $x = $x.clone();)*
$y
}
};
}
which you can use like this:
let val = Rc::new("Hello World".to_string());
closure_func1(enclose! { (val) move || { do_stuff1(val) } });
closure_func2(enclose! { (val) move || { do_stuff2(val) } });
closure_func3(enclose! { (val) move || { do_stuff3(val) } });
Playground Example
It is slightly more general than user4815162342's solution in that you can specify any number of values of any type as long as they can be cloned.
I also found the closure crate which allows you to specify any combination of moves, clones and others. You would use that like this:
let val = Rc::new("Hello World".to_string());
closure_func1(closure!(clone val, || { do_stuff1(val) } ));
closure_func2(closure!(clone val, || { do_stuff2(val) } ));
closure_func3(closure!(clone val, || { do_stuff3(val) } ));

Related

How to use multiple macros inside macros in Rust?

I’d like to have a code that supposed to achieve this in end.
counters!(NAME1, “unit1”, NAME2, “unit2”)
// generates
const NAME1 = 0;
const NAME2 = 1;
static mut counters = [AtomicUsize::new(0), AtomicUsize::new(0)];
static units = [“unit1”, “unit2”];
So far I’ve been able to create indices names and the array of arbitrary values, but I have troubles combining this things together.
playgound link
use std::sync::atomic::AtomicUsize;
macro_rules! gen_array {
($out:expr; ) => { $out };
([$($out:tt)*]; $name:ident, $($names:tt)*) => {
gen_array!([$($out)* $name,]; $($names)*)
};
}
macro_rules! gen_vars {
($cnt:expr; ) => {};
($cnt:expr; $name:ident, $($names:tt)*) => {
const $name: usize = $cnt;
gen_vars!($cnt + 1; $($names)*)
};
}
macro_rules! counters {
($($name:ident),+) => {
gen_vars!(0; $($name),+,);
gen_array!([]; $($name),+,);
};
}
fn main() {
let arr = counters!(ONE, TWO);
dbg!(arr);
}
This seems to do what you want.
use std::sync::atomic::AtomicUsize;
macro_rules! gen_array {
($out:expr; ) => { $out };
([$($out:tt)*]; $name:literal, $($names:tt)*) => {
gen_array!([$($out)* $name,]; $($names)*)
};
}
macro_rules! gen_vars {
($cnt:expr; ) => {};
($cnt:expr; $name:ident, $($names:tt)*) => {
const $name: usize = $cnt;
gen_vars!($cnt + 1; $($names)*)
};
}
macro_rules! counters {
($($name:ident,$value:literal),+) => {
gen_vars!(0; $($name),+,);
gen_array!([]; $($value),+,);
};
}
fn main() {
counters!(ONE, "unit1", TWO, "unit2");
}
Playground

Creating a Custom Colored dbg! Macro In Rust

I'd like to create a custom macro similar to the standard dbg! macro, but with the option to use colors via the colored crate. dbg! usually prints something with the format of
[path_to_file:line_number] "symbol name" = "symbol value"
//[src/gallery/image_slot.rs:231] "my_integer_value_of_12" = "12"
How do I access the path/line number [path_to_file:line_number] so I can print it?
How do I access the symbol name of a variable? (i.e. print my_var given my_var = 12)
Use the file!, line!, and column! macros.
Use the stringify! macro.
If you go to the docs of the dbg! macro, you can click [src], which shows the implementation of dbg!, which is as follows:
macro_rules! dbg {
() => {
$crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!());
};
($val:expr $(,)?) => {
// Use of `match` here is intentional because it affects the lifetimes
// of temporaries - https://stackoverflow.com/a/48732525/1063961
match $val {
tmp => {
$crate::eprintln!("[{}:{}] {} = {:#?}",
$crate::file!(), $crate::line!(), $crate::stringify!($val), &tmp);
tmp
}
}
};
($($val:expr),+ $(,)?) => {
($($crate::dbg!($val)),+,)
};
}
Using that, we can easily create a similar colored_dbg! macro, with the colored crate as you suggested.
(I just picked random colors, for a simple example)
// colored = "2.0"
use colored::Colorize;
macro_rules! colored_dbg {
() => {
eprintln!("{}", format!("[{}:{}]", file!(), line!()).green());
};
($val:expr $(,)?) => {
match $val {
tmp => {
eprintln!("{} {} = {}",
format!("[{}:{}]", file!(), line!()).green(),
stringify!($val).red(),
format!("{:#?}", &tmp).blue(),
);
tmp
}
}
};
($($val:expr),+ $(,)?) => {
($(colored_dbg!($val)),+,)
};
}
You'd use it just like how you'd be able to use dbg!:
fn main() {
let my_var = 12;
colored_dbg!(&my_var);
let v = vec!["foo", "bar", "baz"];
let v = colored_dbg!(v);
}
Which outputs the following:

Check if Option<String> is Some(my_string)

I'd like to know what is the most idiomatic way of checking if a q: Option<String> that I have has the value of a particular string that I have in my_string: String. So the most straightforward solution is:
if q.is_some() && q.unwrap() == my_string
Another one I can think of:
if q.unwrap_or_default() == my_string
but this wouldn't work in the corner case of my_string being empty.
Another one:
match q {
Some(s) if s == my_string => {
...
},
_ => {},
}
but this is very verbose.
Is there something simpler, like some clever if let?
check it directly:
if Some(my_string) == q {
}
or (to keep my_string alive)
if Some(&my_string) == q.as_ref() {
}
There will be (probably) a contains() function in future rust versions which can be used like
if q.contains(&my_string) {
}
It is more flexible because it allows to compare different datatypes (when they implement PartialEq). See https://github.com/rust-lang/rust/issues/62358
I really like the answer provided by #ensc but it consumes my_string; here is a version that does not.
fn main() {
let my_string = String::from("abcd");
let q1: Option<String> = Some(String::from("abcd"));
let q2: Option<String> = Some(String::from("abc"));
let q3: Option<String> = None;
// if Some(my_string) == q1 { // this will CONSUME my_string
if Some(&my_string) == q1.as_ref() {
println!("The same {:?}", q1);
}
// if Some(my_string) == q2 { // this will CONSUME my_string
if Some(&my_string) == q2.as_ref() {
println!("The same {:?}", q2);
}
// if Some(my_string) == q3 { // this will CONSUME my_string
if Some(&my_string) == q3.as_ref() {
println!("The same {:?}", q3);
}
}
Just use if let:
fn main() {
let s = Some("abc".to_string());
if let Some("abc") = s.as_ref().map(|s: &String| s as &str) {
println!("Ok")
}
}
On the Rust book :
let some_u8_value = Some(0u8);
match some_u8_value {
Some(3) => println!("three"),
_ => (),
}
Is equivalent of :
if let Some(3) = some_u8_value {
println!("three");
}

Pass Arc into async handler [duplicate]

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 };
}

What's the best way to mutate a nested enum?

I have an enum which roughly looks like this simplified example:
use std::collections::BTreeMap;
enum Value {
Null,
Object(BTreeMap<String, Value>)
}
Now I would like to, based on a list of field names, drill down into a Value::Object and initialize it with the given fields. The leaf field should always receive the Value::Null variant.
What I would like to, and am used to, do is the following:
fn set_null_to_how_i_want_it(fields: &[&str], mut v: &mut Value) {
debug_assert!(fields.len() > 0);
for (fid, field) in fields.iter().enumerate() {
v =
match *v {
Value::Object(ref mut map) => {
let val_to_insert =
if fid == fields.len() - 1 {
Value::Null
} else {
Value::Object(Default::default())
};
map.entry(field.to_string()).or_insert(val_to_insert)
}
_ => unreachable!(),
}
}
}
However, the borrow checker will not allow it.
Interestingly, what worked is the following, more complex and probably less performant implementation:
fn set_null_how_borrow_chk_allows_it(fields: &[&str], v: &mut Value) {
let next =
match *v {
Value::Object(ref mut map) => {
let val_to_insert =
if fields.len() == 1 {
Value::Null
} else {
Value::Object(Default::default())
};
map.entry(fields[0].to_string()).or_insert(val_to_insert)
},
_ => unreachable!()
};
if fields.len() > 1 {
set_null_how_borrow_chk_allows_it(&fields[1..], next)
}
}
With the version above, all the following code runs fine:
let mut v = Value::Object(Default::default());
let fields = ["foo", "bar", "baz"];
set_null_how_borrow_chk_allows_it(&fields, &mut v);
let mut map_count = 0;
for (fid, field) in fields.iter().enumerate() {
let next =
match v {
Value::Object(mut map) => {
map_count += 1;
map.remove(&field.to_string()).unwrap()
},
_ => unreachable!()
};
v = next;
}
assert_eq!(map_count, fields.len());
match v {
Value::Null => (),
Value::Object(_) => unreachable!(),
}
Is there a better way to initialize a nested enumeration or to get set_null_to_how_i_want_it(...) to work ?
How to reproduce
You can have a look at the complete example on github, and play around with it as follows:
git clone https://github.com/Byron/depot
cd depot/src/rust/hello
cargo test --test lang
# edit src/rust/hello/tests/lang.rs for testing
Meta
➜ hello git:(master) ✗ rustc --version --verbose
rustc 1.1.0-nightly (4b88e8f63 2015-05-11) (built 2015-05-12)
binary: rustc
commit-hash: 4b88e8f63eeaf557c916a0a1e73150b028c44c52
commit-date: 2015-05-11
build-date: 2015-05-12
host: x86_64-apple-darwin
release: 1.1.0-nightly
The borrow checker works on names, and so some examples like your first approach don’t work; this can be worked around by moving the value v to a different name first and then assigning the new value to v:
fn set_null_to_how_i_want_it(fields: &[&str], mut v: &mut Value) {
debug_assert!(fields.len() > 0);
for (fid, field) in fields.iter().enumerate() {
let tmp = v;
v = match *tmp {
Value::Object(ref mut map) => {
let val_to_insert =
if fid == fields.len() - 1 {
Value::Null
} else {
Value::Object(Default::default())
};
map.entry(field.to_string()).or_insert(val_to_insert)
}
_ => unreachable!(),
};
}
}

Resources