Is it possible to compile a specific closure to wasm in rust? - rust

Here's my main function as
fn main() {
let v = vec![1, 2, 3];
let z = 123;
let w: Vec<_> = v
.iter()
.map(|x| {
// closure A
println!("v = {x}");
z + x * x
})
.collect();
println!("{:?}", w);
}
The closure enclosing comment closure A may reference other crates' APIs sometimes.
Is there a way to compile only the closure enclosing comment closure A (rather than the whole main function) to WebAssembly?

Related

Non-lexical lifetimes

Can someone explain the following, please?
this compiles (explanation: NLL y not referenced after initial definition?)
fn main() {
let mut x = 5;
let y = &x;
let z = &mut x;
println!("z: {}", z);
}
this doesn't compile (explanation: z not referenced but only introduced the line before so still active?)
fn main() {
let mut x = 5;
let y = &x;
let z = &mut x;
println!("y: {}", y);
}
this compiles (explanation: NLL z not referenced after initial definition?)
fn main() {
let mut x = 5;
let z = &mut x;
let y = &x;
println!("y: {}", y);
}
this doesn't compile (just to see whether introducing lines would lead to z not being active by the println)
fn main() {
let mut x = 5;
let y = &x;
let z = &mut x;
let foo = String::from("foo");
println!("y: {}, foo: {}", y, foo);
}
I'm confused... I couldn't find anything that covers this specific case in the book but if somebody has a link to something that explains this behaviour, I would appreciate it.
fn main() {
let mut x = 5;
let y = &x;
// 'y lifetime starts, holding an immutable reference to x
// 'y lifetime ends (never used later), releasing hold on x
let z = &mut x; // this is fine because the hold is released
println!("z: {}", z);
}
fn main() {
let mut x = 5;
let y = &x;
// 'y lifetime starts, holding an immutable reference to x
let z = &mut x; // this is forbidden because of the existing hold
println!("y: {}", y);
// 'y lifetime ends, releasing hold on x
}
fn main() {
let mut x = 5;
let z = &mut x;
// 'z lifetime starts, holding a mutable reference to x
// 'z lifetime ends (never used later), releasing hold on x
let y = &x; // this is fine because the hold is released
println!("y: {}", y);
// 'y lifetime ends, releasing hold on x
}
Pretty much the same as #2
fn main() {
let mut x = 5;
let y = &x;
// 'y lifetime starts, holding an immutable reference to x
let z = &mut x; // this is forbidden because of the existing hold
let foo = String::from("foo");
println!("y: {}, foo: {}", y, foo);
// 'y lifetime ends, releasing hold on x
}
As you know, no other references can exist while a mutable reference to some data also exists. You will see &mut also called "exclusive references" for this reason.
The borrow checker is what enforces this, using the lifetimes of the references in your code. In older versions of Rust, all lifetimes were "lexical" - they would last as long as their containing scope. "Non-lexical lifetimes" were introduced to make things easier for the programmer, by making it so reference lifetimes would only last as long as those references were used.
This is what allows examples #1 and #3 to work. A reference is created but the lifetime immediately ends because they aren't used later, so there is no overlap of lifetimes when the next line creates a different reference.
It's useful to look at the lifetime of every variable here. Let's look example by example.
// example one
fn main() {
let mut x = 5;
let y = &x; // y is declared here, but never used
// so its lifetime is effectively nil
let z = &mut x; // by this line, it no longer exists
println!("z: {}", z);
}
// example two
fn main() {
let mut x = 5;
let y = &x; // y is declared here and used in the
// println, so...
let z = &mut x; // ...this is invalid, since you cannot
// take a mutable reference when you have
// an existing reference.
println!("y: {}", y);
}
// example three
fn main() {
let mut x = 5;
let z = &mut x; // z is declared here but never used
// so its lifetime is effectively nil
let y = &x; // by this line, it no longer exists
println!("y: {}", y);
}
// example four
fn main() {
let mut x = 5;
let y = &x;
let z = &mut x; // This is functionally identical to ex. 2
let foo = String::from("foo");
println!("y: {}, foo: {}", y, foo);
}

What is a reborrow and how does it influence the code the compiler generates?

Part of the assert_eq macro code is:
($left:expr, $right:expr, $($arg:tt)+) => ({
match (&($left), &($right)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
// The reborrows below are intentional. Without them, the stack slot for the
// borrow is initialized even before the values are compared, leading to a
// noticeable slow down.
$crate::panic!(r#"assertion failed: `(left == right)`
left: `{:?}`,
right: `{:?}`: {}"#, &*left_val, &*right_val,
$crate::format_args!($($arg)+))
}
}
}
});
The comment says that the reborrow is intentional and that it would somehow influence how stack is used.
What is a reborrow and how does it influence the code the compiler generates?
I am not sure how it affects compilation but a reborrow is when you dereference something and then borrow it straight after.
For example:
fn main() {
let mut vec: Vec<u8> = vec![1, 2, 3];
let mut_ref: &mut Vec<u8> = &mut vec;
let reborrow: &Vec<u8> = &*mut_ref;
}
It can be used to:
get an immutable reference from a mutable reference (code above)
get a reference with a shorter lifetime
get a reference to something in a smart pointer
get a reference from a pointer
and probably other things too.. (I am fairly new to Rust 😃)
Example use for shortening lifetime (very contrived but this is oversimplified):
fn main() {
let mut outer_vec = vec![1, 2, 3];
let outer_ref = &mut outer_vec;
{
// shorten lifetime of outer_ref
// not doing this causes an error
let mut outer_ref = &mut *outer_ref; // mutable reborrow
let mut inner_vec = vec![1, 2, 3];
let inner_ref = &mut inner_vec;
// imagine a real condition
if true {
outer_ref = inner_ref;
}
// use outer_ref which could point to the outer_vec or inner_vec
println!("{:?}", outer_ref);
}
println!("{:?}", outer_ref);
}
Getting a reference to something behind a smart pointer (Box in this case):
fn main() {
let vec = vec![1, 2, 3];
let boxed = Box::new(vec);
let reborrow: &Vec<u8> = &*boxed;
println!("{:?}", reborrow);
}
Reference from pointer:
fn main() {
let num: u8 = 10;
let pointer: *const u8 = &num as *const u8;
unsafe {
let ref_from_ptr: &u8 = &*pointer;
}
}
Not sure if all of these are strictly considered a "reborrow" by the way.

Mutable vs. immutable borrows in closure?

I can't figure out how to get the following to work. I think I need the closure to borrow by &mut Vec, but I don't know how to express that. This is distilled from a larger function, but shows the same error.
fn main() {
let mut v = vec![0; 10];
let next = |i| (i + 1) % v.len();
v[next(1usize)] = 1;
v.push(13);
v[next(2usize)] = 1;
}
Error:
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> a.rs:9:5
|
5 | let next = |i| {
| --- immutable borrow occurs here
6 | (i + 1) % v.len()
| - first borrow occurs due to use of `v` in closure
...
9 | v[next(1usize)] = 1;
| ^ ---- immutable borrow later used here
| |
| mutable borrow occurs here
error: aborting due to previous error
If you really want to do it with a closure, you will have to pass the vector by parameter:
let next = |v: &Vec<_>, i| (i + 1) % v.len();
This makes the closure borrow per-call, rather than capture for the scope. You still need to separate the borrows, though:
let j = next(&v, 1usize);
v[j] = 1;
To make your life easier, you can put everything inside the closure instead:
let next = |v: &mut Vec<_>, i, x| {
let j = (i + 1) % v.len();
v[j] = x;
};
Which allows you to simply do:
next(&mut v, 1usize, 1);
next(&mut v, 2usize, 2);
// etc.
This pattern is useful for cases where you are writing a closure just for avoiding local code repetition (which I suspect is why you are asking given the comments).
Since the closure only needs the length of the Vec. Then instead, you can just get that prior to the closure. Then you avoid the whole borrowing issue, as the closure doesn't need to borrow v anymore.
fn main() {
let mut v = vec![0; 10];
let len = v.len();
let next = |i| (i + 1) % len;
v[next(1usize)] = 1;
}
Assuming your closure is not dependent on other things, then instead of a closure, you could define a trait with a method that does that.
For simplicity let's call the trait VecExt and the method set.
trait VecExt<T> {
fn set(&mut self, index: usize, value: T);
}
impl<T> VecExt<T> for Vec<T> {
fn set(&mut self, index: usize, value: T) {
let len = self.len();
self[(index + 1) % len] = value;
}
}
fn main() {
let mut v = vec![0; 10];
v.set(1, 1);
v.push(13);
v.set(2, 1);
}
A closure probably isn't the right tool for the job. The compiler is unhappy because your closure has taken a reference against your Vec, but then while that closure reference is still outstanding you're trying to mutate the Vec. Under Rust's borrow rules, that's not allowed.
The most straightforward approach would be storing your data inside a struct, and making next a member function. That way, there's no closure taking references; it can just check the length only when needed.
struct WrapVec<T>(Vec<T>);
impl<T> WrapVec<T> {
fn wrap_next(&mut self, index: usize) -> &mut T {
let index = (index + 1) % self.0.len();
&mut self.0[index]
}
}
fn main() {
let mut v = WrapVec(vec![0; 10]);
*v.wrap_next(1) = 1;
v.0.push(13);
*v.wrap_next(2) = 1;
}
If you want to be able to apply this function to any Vec, then you may find it useful to define a new trait. For example:
trait WrapNext<T> {
fn wrap_next(&mut self, index: usize) -> &mut T;
}
impl<T> WrapNext<T> for Vec<T> {
fn wrap_next(&mut self, index: usize) -> &mut T {
let index = (index + 1) % self.len();
&mut self[index]
}
}
fn main() {
let mut v = vec![0; 10];
*v.wrap_next(1) = 1;
v.push(13);
*v.wrap_next(2) = 1;
}
In addition to the other answers here, you can use a macro to scope v so you don't have to pass it in every call:
fn main() {
let mut v = vec![0; 10];
macro_rules! next {
// rule to get an index
($i: expr) => {
($i + 1) % v.len()
};
// rule to mutate the vector
($i: expr => $v: expr) => {{
let ind = next!($i);
v[ind] = $v;
}};
};
// get an index
let ind = next!(1usize);
// mutate the vector
v[ind] = 1;
v.push(13);
// or, with the mutation syntax
next!(2usize => 3);
println!("{:?}", v);
}

Borrowing mutable twice while using the same variable

Suppose that I'm going through a vector (not necessarily linearly, so I can't just use map) and I need to change an element when it satisfies some condition. I would think to use some variable to keep track of where I am, for example, something like a current variable
let mut v = vec![1, 2, 3, 4];
let mut current = &mut v[0];
and then check current to for some condition to see if it needs to be changed. However, when I do
current = &mut v[1];
It gives me the cannot borrow v as mutable more than once at a time.
I feel like this should be allowed, since I've only used one variable, and I can't access the old borrow any more.
Is there some way I can let rust know that I'm giving the first borrow back, so I'm not borrowing twice? Or have I been thinking about this wrong, and there is a different rust idiom I should use? I've solved this problem by using the indeces for the vector instead of a mutable reference, but I think this problem of "traversing using a current and then changing it" goes beyond just vectors. What if the data structure I had didn't have indeces?
The mutable reference exists until the variable goes out of scope, so you can have several mutable borrows in sequence by putting blocks around each one:
fn do_stuff(n: &mut usize) {
*n += 1;
}
fn main() {
let mut v = vec![1, 2, 3, 4];
{
let current = &mut v[1];
do_stuff(current);
}
{
let current = &mut v[0];
do_stuff(current);
}
println!("{:?}", v);
}
This is unnecessary with non-lexical lifetimes, which are currently only available on the nightly version:
#![feature(nll)]
fn do_stuff(n: &mut usize) {
*n += 1;
}
fn main() {
let mut v = vec![1, 2, 3, 4];
let mut current = &mut v[1];
do_stuff(current);
current = &mut v[0];
do_stuff(current);
println!("{:?}", v);
}
If you want to access more than one, you have to create a scope.
fn main() {
let mut vec = vec![2, 3, 5];
{
let mut current1 = vec.get_mut(1);
println!("{:?}", current1);
}
{
let mut current2 = vec.get_mut(2);
println!("{:?}", current2);
}
for i in 0..3 {
let mut current = vec.get_mut(i);
println!("{:?}", current);
}
}

How to fold using a HashMap as an accumulator?

This code works:
let stdin = std::io::stdin();
let mut rdr = csv::Reader::from_reader(stdin);
let mut hmap = HashMap::<String, u64>::new();
rdr.records()
.map(|r| r.unwrap())
.fold((), |_, item| {
// TODO: Is there a way not to have to copy item[col] every time?
let counter = hmap.entry(item[col].to_string()).or_insert(0);
*counter += 1;
});
This code fails with the message: "cannot move out of acc because it is borrowed"
let stdin = std::io::stdin();
let mut rdr = csv::Reader::from_reader(stdin);
let hmap = rdr.records()
.map(|r| r.unwrap())
.fold(HashMap::<String, u64>::new(), |mut acc, item| {
// TODO: Is there a way not to have to copy item[col] every time?
let counter = acc.entry(item[col].to_string()).or_insert(0);
*counter += 1;
acc
});
You cannot return acc from the closure because you have a mutable borrow to it that still exists (counter).
This is a limitation of the Rust compiler (specifically the borrow checker). When non-lexical lifetimes are enabled, your original code will work:
#![feature(nll)]
use std::collections::HashMap;
fn main() {
let hmap = vec![1, 2, 3].iter().fold(HashMap::new(), |mut acc, _| {
let counter = acc.entry("foo".to_string()).or_insert(0);
*counter += 1;
acc
});
println!("{:?}", hmap);
}
Before NLL, the compiler is overly conservative about how long a borrow will last. To work around this, you can introduce a new scope to constrain the mutable borrow:
use std::collections::HashMap;
fn main() {
let hmap = vec![1, 2, 3].iter().fold(HashMap::new(), |mut acc, _| {
{
let counter = acc.entry("foo".to_string()).or_insert(0);
*counter += 1;
}
acc
});
println!("{:?}", hmap);
}
You can also prevent the borrow from lasting beyond the line it's needed in:
use std::collections::HashMap;
fn main() {
let hmap = vec![1, 2, 3].iter().fold(HashMap::new(), |mut acc, _| {
*acc.entry("foo".to_string()).or_insert(0) += 1;
acc
});
println!("{:?}", hmap);
}
I assumed Rust would know that counter would go out of scope once acc was returned
This is understandable and relates to the non-lexical lifetimes discussion. The "good" news is that Rust is being consistent about how references work when the thing being referenced moves. In this case, you are moving the accumulator into an "output slot". You can see this with plain functions as well:
fn foo(mut s: Vec<u8>) -> Vec<u8> {
let borrow = &mut s[0];
s
}
fn main() {}
But really, it's the same as moving a referred-to variable at all:
fn main() {
let mut s = Vec::<u8>::new();
let borrow = &mut s[0];
let s2 = s;
}
Both of these fail before NLL and work afterwards.

Resources