I'm trying to provide a closure via a C callback using a static variable. I was able to get things working with a Fn type, but I'd like to make it work via FnMut to provide users of the library with more versatility.
Here's what I have:
lazy_static! {
static ref CALLBACK: Mutex<RefCell<Box<FnMut(Result<&str>) + Send>>> = Mutex::new(RefCell::new(Box::new(|_|())));
}
fn wrap_cb<F: Fn(Result<&str>)>(f: Option<F>) -> Option<unsafe extern "C" fn(*mut c_char, size_t)> {
match f {
Some(_) => {
unsafe extern "C" fn wrapped(msg: *mut c_char, len: size_t) {
let s = std::str::from_utf8(std::slice::from_raw_parts(msg as *const u8, len))
.map_err(Error::from);
let x = CALLBACK.lock().unwrap();
x.borrow_mut()(s);
}
Some(wrapped)
}
None => None,
}
}
This gives the error:
error[E0596]: cannot borrow immutable `Box` content as mutable
--> src/wpactrl.rs:56:17
|
56 | x.borrow_mut()(s);
| ^^^^^^^^^^^^^^ cannot borrow as mutable
It looks like the "cannot borrow immutable Box content as mutable" problem reduces to:
fn invoke(m: &Mutex<RefCell<Box<FnMut()>>>) {
let r = m.lock().unwrap();
r.borrow_mut()();
}
I haven't yet figured out why this works, but it does work if changed to:
fn invoke(m: &Mutex<RefCell<Box<FnMut()>>>) {
let r = m.lock().unwrap();
let f = &mut *r.borrow_mut();
f();
}
Related
I'm having trouble initializing a fixed length array. My attempts so far all result in the same "use of possibly uninitialized variable: foo_array" error:
#[derive(Debug)]
struct Foo { a: u32, b: u32 }
impl Default for Foo {
fn default() -> Foo { Foo{a:1, b:2} }
}
pub fn main() {
let mut foo_array: [Foo; 10];
// Do something here to in-place initialize foo_array?
for f in foo_array.iter() {
println!("{:?}", f);
}
}
error[E0381]: use of possibly uninitialized variable: `foo_array`
--> src/main.rs:13:14
|
13 | for f in foo_array.iter() {
| ^^^^^^^^^ use of possibly uninitialized `foo_array`
I implemented the Default trait, but Rust does not seem to call this by default akin to a C++ constructor.
What is the proper way to initialize a fixed length array? I'd like to do an efficient in-place initialization rather than some sort of copy.
Related: Why is the Copy trait needed for default (struct valued) array initialization?
Related: Is there a way to not have to initialize arrays twice?
The safe but somewhat inefficient solution:
#[derive(Copy, Clone, Debug)]
struct Foo {
a: u32,
b: u32,
}
fn main() {
let mut foo_array = [Foo { a: 10, b: 10 }; 10];
}
Since you're specifically asking for a solution without copies:
use std::mem::MaybeUninit;
#[derive(Debug)]
struct Foo {
a: u32,
b: u32,
}
// We're just implementing Drop to prove there are no unnecessary copies.
impl Drop for Foo {
fn drop(&mut self) {
println!("Destructor running for a Foo");
}
}
pub fn main() {
let array = {
// Create an array of uninitialized values.
let mut array: [MaybeUninit<Foo>; 10] = unsafe { MaybeUninit::uninit().assume_init() };
for (i, element) in array.iter_mut().enumerate() {
let foo = Foo { a: i as u32, b: 0 };
*element = MaybeUninit::new(foo);
}
unsafe { std::mem::transmute::<_, [Foo; 10]>(array) }
};
for element in array.iter() {
println!("{:?}", element);
}
}
This is recommended by the documentation of MaybeUninit.
You can use the arrayvec crate:
Cargo.toml
[package]
name = "initialize_array"
version = "0.1.0"
edition = "2018"
[dependencies]
arrayvec = "0.7.2"
src/main.rs
use arrayvec::ArrayVec;
use std::iter;
#[derive(Clone)]
struct Foo {
a: u32,
b: u32,
}
fn main() {
let foo_array: [Foo; 10] = iter::repeat(Foo { a: 10, b: 10 })
.take(10)
.collect::<ArrayVec<_, 10>>()
.into_inner()
.unwrap_or_else(|_| unreachable!());
}
The easiest way is to derive Copy on your type and initialize the array with that, copying the element N times:
#[derive(Copy)]
struct Foo {
a: u32,
b: u32,
}
let mut foo_array = [Foo { a: 1, b: 2 }; 10];
If you want to avoid copying, there are a couple options. You can use the Default trait:
let mut foo_array: [Foo; 10] = Default::default();
However, this is limited to arrays up to 32 elements. With const generics, it is now possible for the standard library to provide Default for all arrays. However, this would be a backward incompatible change for subtle reasons that are being worked on.
For now, you can take advantage of the fact that const values are also allowed in array repetition expressions:
const FOO: Foo = Foo { a: 1, b: 2 };
let mut foo_array = [FOO; 10];
If you're on nightly, you can use array::map:
#![feature(array_map)]
let mut foo_array = [(); 10].map(|_| Foo::default())
I have a C library that expects string type that explicitly defines the string length:
#[repr(C)]
pub struct FFIStr {
len: usize,
data: *const u8,
}
Because this type is used as a static, I'd like a way to safely declare it using a const function or macro (instead of manually setting len).
My first attempt was to use a macro and len(), however in versions before 1.39.0, it is not possible to get the length of a slice as a const fn:
macro_rules! ffi_string {
($x:expr) => {
FFIStr { len: $x.len(), data: $x as *const u8 }
};
}
#[no_mangle]
pub static mut HELLO_WORLD: FFIStr = ffi_string!(b"Hello, world!");
error: core::slice::<impl [T]>::len` is not yet stable as a const function
My second attempt was to use std::mem::size_of<T>, but there doesn't appear to be a way to get the type of the static array short of using generics:
const fn ffi_string<T>(s: &'static T) -> FFIStr {
FFIStr { len: ::std::mem::size_of::<T>(), data: s as *const _ as *const _ }
}
#[no_mangle]
pub static mut HELLO_WORLD: FFIStr = ffi_string(b"Hello, world!");
While this works (surprisingly), it's horribly prone to misuse as it wildly casts whatever you pass it to a *const u8.
It seems like const_generics would be a nice solution to this, but they're currently unstable:
const fn ffi_string<const SIZE: usize>(s: &'static [u8; SIZE]) -> FFIStr {
FFIStr { len: SIZE, data: s as *const u8 }
}
#[no_mangle]
pub static mut X: FFIStr = ffi_string(b"Hello, world!");
error[E0658]: const generics are unstable
Is there a better way of determining the size of a static array at compile time?
In Rust 1.39.0 [T]::len was stabilised as a const function, now making this straight forward:
const ARRAY: [i32; 3] = [1, 2, 3];
const ARRAY_SIZE: usize = ARRAY.len();
fn main() {
assert_eq!(3, ARRAY_SIZE);
}
In earlier versions of Rust, here's one way based on the common C ARRAY_SIZE macro:
macro_rules! array_size {
($x:expr) => (
(size_of_val($x) / size_of_val(&$x[0]))
)
}
const fn size_of_val<T>(_: &T) -> usize {
std::mem::size_of::<T>()
}
fn main() {
assert_eq!(3, array_size!(&[1, 2, 3]));
assert_eq!(13, array_size!(b"Hello, world!"));
}
It uses a const generic function size_of_val<T> to determine the type and thus the size of a value passed by reference (the built-in std::mem::size_of_val isn't const).
Note: This doesn't work for arrays of size 0. This can be fixed by using size_of_val($x) / size_of_val(unsafe { &*$x.as_ptr() }) at the cost of wrongly accepting non-array types (e.g. &String).
I have implemented a struct inside a module. I am trying to implement the io::Read trait for a reference slice of the struct.
Here is a simplified version of my code. For now the new trait implementation is inefficient. I am trying different things to make it work.
struct mytype {
inner: f32,
}
impl io::Read for mytype {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
buf.write_u32::<LittleEndian>(self.inner.to_bits()).unwrap();
Ok(4)
}
}
impl<'a> io::Read for &'a [mytype] {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let mut vec8: Vec<u8> = vec![];
for t in self.iter() {
match (*t).read_u32::<LittleEndian>() {
Ok(u) => vec8.write_u32::<LittleEndian>(u).unwrap(),
Err(x) => (),
}
}
for (ind, it) in vec8.iter().enumerate() {
buf[ind] = *it;
}
Ok(vec8.len())
}
}
The rust compiler keeps complaining about the code with this error:
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> src\lib.rs:37:1
|
37 | impl<'a> io::Read for &'a [mytype] {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
|
= note: the impl does not reference any types defined in this crate
= note: define and implement a trait or new type instead
Just implementing io::Read for mytype works correctly.
I'm trying to model a dataframe-like structure. I know how use enums here, but I'm exploring how do it similar to C#/Python/etc.
I tried to follow Rust Trait object conversion but things are not working:
use std::any::{Any};
use std::fmt::Debug;
pub trait Value: Any + Sized {
fn as_any(&self) -> &Any {
self
}
fn as_any_mut(&mut self) -> &mut Any {
self
}
}
impl Value for i32 {}
#[derive(Debug)]
struct Frame {
data: Vec<Box<Any>>,
}
fn make_int(of: Vec<i32>) -> Frame {
let data = of.into_iter().map(|x| Box::new(x.as_any())).collect();
Frame {
data: data,
}
}
The compiler complains:
error[E0277]: the trait bound `std::vec::Vec<std::boxed::Box<std::any::Any>>: std::iter::FromIterator<std::boxed::Box<&std::any::Any>>` is not satisfied
--> src/main.rs:40:61
|
40 | let data = of.into_iter().map(|x| Box::new(x.as_any())).collect();
| ^^^^^^^ a collection of type `std::vec::Vec<std::boxed::Box<std::any::Any>>` cannot be built from an iterator over elements of type `std::boxed::Box<&std::any::Any>`
|
= help: the trait `std::iter::FromIterator<std::boxed::Box<&std::any::Any>>` is not implemented for `std::vec::Vec<std::boxed::Box<std::any::Any>>`
The main problem is with this function:
fn as_any(&self) -> &Any {
self
}
This means that you can borrow a Value as a &Any, (it converts a &Value into a &Any).
But then, you want to create a Box<Any> from that &Any. That will never work, because &Any is a borrowed value, while Box<Any> is owned.
The easiest solution would be to change the trait to return the boxed value (an owned trait object):
pub trait Value: Any + Sized {
fn as_boxed_any(&self) -> Box<Any> {
Box::new(self)
}
//The mut variation is not needed
}
Now the make_int function is trivial:
fn make_int(of: Vec<i32>) -> Frame {
let data = of.into_iter().map(|x| x.as_boxed_any()).collect();
Frame {
data: data,
}
}
UPDATE: Tinkering a bit, I've found that you can create the Vec<Box<Any>> by writing:
fn make_int(of: Vec<i32>) -> Frame {
let data = of.into_iter().map(|x| Box::new(x) as Box<Any>).collect();
Frame {
data: data,
}
}
If you are writing the trait only for this conversion, you don't actually need it.
I am trying to have a struct which has a field which I assume should be of type Result<TempDir>. When I initialise an implementation of the field with new(), I would like that particular field to be initialised by the creation of a new temp directory. Later, I want to implement a method to read from that directory.
Here's the code, I am more worried about the syntax and proper use of libraries (why exactly are there over four libraries for read/write buffering in Rust, this is insane) as the logic should be right. Dont worry too much about the trait implementations, I just need directions in the syntax. Please don't be too harsh, as I know it doesn't compile, but with just two changes it should.
extern crate rustc_back;
use std::path::Path;
use std::fs::File;
use rustc_back::tempdir::TempDir as TempDir;
pub struct MyStorage {
temp_dir : Result<TempDir>
}
impl MyStorage {
pub fn new() -> MyStorage {
//tempo = match TempDir::new("encrypt_storage");
let store = match TempDir::new("encrypt_storage") {
Ok(dir) => dir,
Err(e) => panic!("couldn't create temporary directory: {}", e)
};
MyStorage { temp_dir: store }
//MyStorage { temp_dir: TempDir::new("encrypt_storage") }
}
}
impl Storage for MyStorage {
fn get(&self, name: Vec<u8>) -> Vec<u8> {
//let mut f = std::fs::File::open(self.temp_dir.path() / name);
let mut f = std::fs::File::open(&self.temp_dir){
// The `desc` field of `IoError` is a string that describes the error
Err(why) => panic!("couldn't open: {}", why.description()),
Ok(file) => file,
};
let mut s = String::new();
//f.read_to_string(&mut s);
match f.read_to_string(&mut s){
Err(why) => panic!("couldn't read: {}", why.description()),
Ok(_) => print!("contains:\n{}", s),
}
s.to_vec()
}
fn put(&mut self, name: Vec<u8>, data: Vec<u8>) {
// self.entries.push(Entry { name : name, data : data })
let mut f = File::create(self.temp_dir.path() / name);
f.write_all(data);
}
fn put(&mut self, name: Vec<u8>, data: Vec<u8>) {
// self.entries.push(Entry { name : name, data : data })
let mut f = File::create(self.temp_dir.path() / name);
f.write_all(data);
}
}
After fixing the indentation (Rust uses 4 spaces per level), removing the Storage for since you didn't provide that trait, removing commented-out code, and adding a main, you are left with this:
extern crate rustc_back;
use std::path::Path;
use std::fs::File;
use rustc_back::tempdir::TempDir as TempDir;
pub struct MyStorage {
temp_dir : Result<TempDir>
}
impl MyStorage {
pub fn new() -> MyStorage {
let store = match TempDir::new("encrypt_storage") {
Ok(dir) => dir,
Err(e) => panic!("couldn't create temporary directory: {}", e)
};
MyStorage { temp_dir: store }
}
}
impl MyStorage {
fn get(&self, name: Vec<u8>) -> Vec<u8> {
let mut f = std::fs::File::open(self.temp_dir.path() / name);
let mut s = String::new();
f.read_to_string(&mut s);
s.to_vec()
}
fn put(&mut self, name: Vec<u8>, data: Vec<u8>) {
let mut f = File::create(self.temp_dir.path() / name);
f.write_all(data);
}
}
fn main() {}
Compiling that has this error:
error: wrong number of type arguments: expected 2, found 1 [E0243]
temp_dir : Result<TempDir>
^~~~~~~~~~~~~~~
Which nicely points to the problematic type. Let's look at the docs for Result, which includes the definition:
pub enum Result<T, E> {
Ok(T),
Err(E),
}
So Result has two type parameters - T is used for the success case, and E is used for the failure case. Your code is only specifying one of them. My guess is that you looked at the docs for TempDir and copy-and-pasted:
fn new(prefix: &str) -> Result<TempDir>
However, if you click on the Result there, you'll see it goes to io::Result, which is simply a type alias that binds E to io::Error:
type Result<T> = Result<T, Error>;
With all that exposition out of the way, you can "fix" your problem by changing your MyStorage struct:
pub struct MyStorage {
temp_dir: std::io::Result<TempDir>,
}
And then you will get another compiler error, as you are already dealing with the Result via the match in MyStorage::new. You aren't storing a io::Result<TempDir>, you are just storing a TempDir! Changing your struct further:
pub struct MyStorage {
temp_dir: TempDir,
}
unlocks a whole new set of errors for you to figure out; but now you have gotten past that first hurdle!