How can a Vec be returned as a typed array with wasm-bindgen? - vector

I have a Vec I would like to return and convert to a typed array with wasm-bindgen, ie, to turn a Vec<u32> into a Uint32Array. From my research it appears that wasm-bindgen cannot handle automatically converting these by itself right now (like it does for String) and instead you must use the js-sys crate. I haven't found clear examples of how to use this crate however. It would be much appreciated if a clear simple example of how to use it could be provided.
For completeness' sake, it would be great if answers could explain both how to expose a function returning a Vec<u32>, as well as a struct member, ie, how do you convert these definitions into something that will work:
#[wasm_bindgen]
pub fn my_func() -> Vec<u32> {
inner_func() // returns Vec<u32>
}
#[wasm_bindgen]
pub struct my_struct {
#[wasm_bindgen(readonly)]
pub my_vec: Vec<u32>,
}

You can convert a Vec<u32> to a js_sys::Uint32Array. So your my_func would look like:
#[wasm_bindgen]
pub fn my_func() -> js_sys::Uint32Array {
let rust_array = inner_func();
return js_sys::Uint32Array::from(&rust_array[..]);
}
And the struct can be exposed by making a getter:
#[wasm_bindgen]
pub struct my_struct {
// Note: not pub
my_vec: Vec<u32>,
}
#[wasm_bindgen]
impl my_struct {
#[wasm_bindgen(getter)]
pub fn my_vec(&self) -> js_sys::Uint32Array {
return js_sys::Uint32Array::from(&self.my_vec[..]);
}
}

Related

What is the most efficient way to return/move a Vec/Field in rust while also emptying it? [duplicate]

I have a struct with a field:
struct A {
field: SomeType,
}
Given a &mut A, how can I move the value of field and swap in a new value?
fn foo(a: &mut A) {
let mut my_local_var = a.field;
a.field = SomeType::new();
// ...
// do things with my_local_var
// some operations may modify the NEW field's value as well.
}
The end goal would be the equivalent of a get_and_set() operation. I'm not worried about concurrency in this case.
Use std::mem::swap().
fn foo(a: &mut A) {
let mut my_local_var = SomeType::new();
mem::swap(&mut a.field, &mut my_local_var);
}
Or std::mem::replace().
fn foo(a: &mut A) {
let mut my_local_var = mem::replace(&mut a.field, SomeType::new());
}
If your type implements Default, you can use std::mem::take:
#[derive(Default)]
struct SomeType;
fn foo(a: &mut A) {
let mut my_local_var = std::mem::take(&mut a.field);
}
If your field happens to be an Option, there's a specific method you can use — Option::take:
struct A {
field: Option<SomeType>,
}
fn foo(a: &mut A) {
let old = a.field.take();
// a.field is now None, old is whatever a.field used to be
}
The implementation of Option::take uses mem::take, just like the more generic answer above shows, but it is wrapped up nicely for you:
pub fn take(&mut self) -> Option<T> {
mem::take(self)
}
See also:
Temporarily move out of borrowed content
Change enum variant while moving the field to the new variant

How to convert Vec<Item> to Vec<String>?

I have the following object, and trying to convert Vec<Courses> and retrieve CourseName.
pub struct Schools {
pub courses: Vec<CourseName>,
}
pub struct CourseName(String);
impl CourseName {
pub fn as_str(&self) -> &str {
&self.0[..]
}
}
Trying to get the Vec<String>, but my following approach does not work,
assigned_courses:Vec<String> = courses.iter().map(|c| c.clone().as_str()).collect()
getting the following error:
value of type `Vec<std::string::String>` cannot be built from `std::iter::Iterator<Item=&str>`
Update:
The map closure receives a &CourseName so clone just copies the reference. What you instead want is to access the tuple and clone the inner String with c.0.
let assigned_courses: Vec<String> = courses.iter().map(|c| c.0.clone()).collect();
Alternatively, if references to the course names are enough, then instead you can use as_str on the inner String.
let assigned_courses: Vec<&str> = schools.courses.iter().map(|c| c.0.as_str()).collect();
To fix the "private field" error. You can add a visibility modifier, e.g.
pub struct CourseName(pub String);
However, it's probably better to keep it as private, and instead add a method like as_str().
impl CourseName {
pub fn as_str(&self) -> &str {
&self.0
}
}
Then resulting in:
let assigned_courses: Vec<String> = schools.courses.iter().map(|c| c.as_str().to_string()).collect();
Alternatively, you could also impl AsRef<str> and/or Display for CourseName, to make everything more generalized.
Assuming that CourseName is just to have a typed version instead of a String. Then you could instead impl Display for CourseName.
use std::fmt;
pub struct CourseName(String);
impl fmt::Display for CourseName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
This allows you to do println!("{}, course") along with course.to_string().
let assigned_courses: Vec<String> = schools.courses.iter().map(|c| c.to_string()).collect();
Working example:
#[derive(Debug)]
pub struct CourseName(pub String);
fn courses_to_strings(list: &[CourseName]) -> Vec<String> {
list.iter().map(|course| course.0.clone()).collect()
}
fn main() {
let courses: Vec<CourseName> = vec![
CourseName("a".to_string()),
CourseName("b".to_string())
];
let strings = courses_to_strings(&courses);
dbg!(strings);
}
playground
All you needed to do was clone the String instead of the CourseName tuple struct in your map function, and also add the pub visibility modifier to the internal String.

How to return a function that returns a trait in Rust

My goal is to implement a function that returns another function, which returns some trait. To be more specific, the returned function should itself return a Future.
To return a function that returns a concrete type, we obviously can do this:
fn returns_closure() -> impl Fn(i32) -> i32 {
|x| x + 1
}
But what if instead of i32 we want to return a Future?
I tried the following:
use futures::Future;
fn factory() -> (impl Fn() -> impl Future) {
|| async {
// some async code
}
}
This does not work because the second impl keyword is not allowed:
error[E0562] `impl Trait` not allowed outside of function and inherent method return types
What is the best way to solve this issue?
I don't know of any way to do this on stable Rust. However, you can use a type alias for an opaque type (also known as existential type) on Rust nightly like this (playground):
#![feature(type_alias_impl_trait)]
use futures::Future;
type Fut<O> = impl Future<Output = O>;
fn factory<O>() -> impl Fn() -> Fut<O> {
|| async {
todo!()
}
}

How do you replace the value of a mutable variable by taking ownership of it?

I am working with a LinkedList and I want to remove all elements which do not pass a test. However, I am running into the error cannot move out of borrowed content.
From what I understand, this is because I am working with &mut self, so I do not have the right to invalidate (i.e. move) one of the contained values even for a moment to construct a new list of its values.
In C++/Java, I would simply iterate the list and remove any elements which match a criteria. As there is no remove that I have yet found, I have interpreted it as an iterate, filter, and collect.
The goal is to avoid creating a temporary list, cloning values, and needing take self and return a "new" object. I have constructed an example which produces the same error. Playground.
use std::collections::LinkedList;
#[derive(Debug)]
struct Example {
list: LinkedList<i8>,
// Other stuff here
}
impl Example {
pub fn default() -> Example {
let mut list = LinkedList::new();
list.push_back(-5);
list.push_back(3);
list.push_back(-1);
list.push_back(6);
Example { list }
}
// Simmilar idea, but with creating a new list
pub fn get_positive(&self) -> LinkedList<i8> {
self.list.iter()
.filter(|&&x| x > 0)
.map(|x| x.clone())
.collect()
}
// Now, attempt to filter the elements without cloning anything
pub fn remove_negative(&mut self) {
self.list = self.list.into_iter()
.filter(|&x| x > 0)
.collect()
}
}
fn main() {
let mut e = Example::default();
println!("{:?}", e.get_positive());
println!("{:?}", e);
}
In my actual case, I cannot simply consume the wrapping object because it needs to be referenced from different places and contains other important values.
In my research, I found some unsafe code which leads me to question if a safe function could be constructed to perform this action in a similar way to std::mem::replace.
You can std::mem::swap your field with a temp, and then replace it with your modified list like this. The big downside is the creation of the new LinkedList. I don't know how expensive that is.
pub fn remove_negative(&mut self) {
let mut temp = LinkedList::new();
std::mem::swap(&mut temp, &mut self.list);
self.list = temp.into_iter()
.filter(|&x| x > 0)
.collect();
}
If the goal is not clone you may use a reference-counting pointer: the clone method on Rc increments the reference counter.
use std::collections::LinkedList;
use std::rc::Rc;
#[derive(Debug)]
struct Example {
list: LinkedList<Rc<i8>>,
// ...
}
impl Example {
pub fn default() -> Example {
let mut list = LinkedList::new();
list.push_back(Rc::new(-5));
list.push_back(Rc::new(3));
list.push_back(Rc::new(-1));
list.push_back(Rc::new(6));
Example { list }
}
// Simmilar idea, but with creating a new list
pub fn get_positive(&self) -> LinkedList<Rc<i8>> {
self.list.iter()
.filter(|&x| x.as_ref() > &0)
.map(|x| x.clone())
.collect()
}
// Now, attempt to filter the elements without cloning anything
pub fn remove_negative(&mut self) {
self.list = self.list.iter()
.filter(|&x| x.as_ref() > &0)
.map(|x| x.clone())
.collect()
}
}
fn main() {
let mut e = Example::default();
e.remove_negative();
println!("{:?}", e.get_positive());
println!("{:?}", e);
}

Returning Error Enumeration with an Arbitrary Variable

I have a function in Rust using try! that attempts to collect all files in a directory recursively and insert them into a vector. Because the function uses try! to check errors, the compiler seems to expect an io::Result return from the function, and doesn't let me include the vector because the try! macro only returns a result. I need the vector to be returned.
Code is as follows:
mod os{
use std::io;
use std::fs::{self, DirEntry};
//use std::fs;
use std::path::Path;
// one possible implementation of walking a directory only visiting files
pub fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> (io::Result<()>,Vec<String>) {
let mut filevec: Vec<String> = Vec::new();
if try!(fs::metadata(dir)).is_dir() {
for entry in try!(fs::read_dir(dir)) {
let entry = try!(entry);
if try!(fs::metadata(entry.path())).is_dir() {
try!(visit_dirs(&entry.path(), cb));
} else {
cb(&entry);
}
}
}
(Ok(()),filevec)
}
fn push_path_to_vec(p:&DirEntry,v:Vec<String>){
v.push(p.path().to_str().unwrap().to_string());
}}
Here is the error:
<std macros>:5:8: 6:42 error: mismatched types:
expected `(core::result::Result<(), std::io::error::Error>, collections::vec::Vec<collections::string::String>)`
found `core::result::Result<_, _>`
(expected tuple,
found enum `core::result::Result`) [E0308]
I wonder if there's any idiomatic way to do this that I've missed.
The return type of visit_dirs is wrong. The function should return a Result, but right now it returns a tuple. Since try! only works for functions returning a Result, your code doesn't compile. You can change the return value of visit_dirs in order to fix it:
pub fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<Vec<String>>
The new definition means that a Vec<String> will be stored in the Result upon success. With some minor tweaks, the code is accepted by the compiler (see below)
mod os{
use std::io;
use std::fs::{self, DirEntry};
//use std::fs;
use std::path::Path;
// one possible implementation of walking a directory only visiting files
pub fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<Vec<String>> {
let mut filevec: Vec<String> = Vec::new();
if try!(fs::metadata(dir)).is_dir() {
for entry in try!(fs::read_dir(dir)) {
let entry = try!(entry);
if try!(fs::metadata(entry.path())).is_dir() {
try!(visit_dirs(&entry.path(), cb));
} else {
cb(&entry);
}
}
}
Ok(filevec)
}
fn push_path_to_vec(p:&DirEntry,mut v:Vec<String>){
v.push(p.path().to_str().unwrap().to_string());
}}

Resources