How can I create a new vector with the iterator Rust macro syntax?
I am trying this:
unsafe {
MUT_STATIC_VAR = vec![
#(#my_outher_vector_data)*,
];
}
Full explanation: I am trying to reasign data that I write in one mut static var of type: Vec when the macro it's spanded at compile time. When I try to retrieve the data at runtime, the global it's empty, so I am rewiring the data that I want in main().
Recap. I am just want to assign the content of one vector to another, but neither array or Vec<T> implements ToTokens.
Compiler error:
`main` function not found in crate `my_crate`
Thanks
To initialize the content, Iterators are able to use macro #(#...)*, syntax.
let other_as_iter = my_outher_vector_data.iter();
quote {
unsafe {
MUT_STATIC_VAR = vec![
#(#other_as_iter)*,
];
}
}
I think lazy_static should do the job:
#[macro_use]
extern crate lazy_static;
use std::sync::Mutex;
lazy_static! {
static ref MUT_STATIC_VAR: Mutex<Vec<String>> = Mutex::new(vec![]);
}
fn other_vec(v: Vec<String>) {
let mut r = MUT_STATIC_VAR.lock().unwrap();
r.extend_from_slice(v.as_slice());
}
fn main() {
other_vec(vec!["dog".to_string(), "cat".to_string(), "mouse".to_string()]);
}
…or draining the other vec after initializing MUT_STATIC_VAR:
fn other_vec(v: &mut Vec<String>) {
let mut r = MUT_STATIC_VAR.lock().unwrap();
r.extend_from_slice(v.drain(..).as_slice());
}
fn main() {
other_vec(&mut vec!["dog".to_string(), "cat".to_string(), "mouse".to_string()]);
}
…or my_other_vector_data wrapped in other_vec! macro:
Playground
macro_rules! other_vec {
() => {
vec!["dog", "cat", "mouse"] // my_other_vector_data here
};
}
Related
Using an async predicate to filter a list of values makes Rust complain about lifetimes. Even if the collection is awaited, which means the predicate will not outlive the filtered value, Rust remains skeptical.
Full repro below with playground here. Note that it filters on a non-copy struct we'd rather pass by reference, rather than a simple value we could just copy and forget without incurring in overhead.
use futures::stream::iter;
use futures::StreamExt;
#[derive(Debug)]
struct Foo {
bar: usize
}
impl Foo {
fn new(bar: usize) -> Self {
Self {
bar
}
}
}
#[tokio::main]
async fn main() {
let arr = vec![
Foo::new(0),
Foo::new(1),
Foo::new(2)
];
let filtered = iter(arr)
.filter(|f| async {compute_baz(f).await > 0})
.collect::<Vec<_>>()
.await;
// should print Foo{bar:1} and Foo{bar:2}
println!("{:?}", filtered)
}
async fn compute_baz(foo: &Foo) -> usize {
// ...do lengthy task...
foo.bar
}
Update
As #Ceasar pointed out below, the async functions are not run in parallel, can that be done?
I'm trying to do something like:
let filter_mask = join_all(items.map(predicate));
let filtered = items.filter(|i| filter_mask[i]).collect::<Vec<_>>();
without the clutter.
An easy workaround is to avoid the closure:
let mut filtered = vec![];
for f in arr.iter() {
if compute_baz(f).await > 0 {
filtered.push(f);
}
}
I'm using the enum_dispatch crate and want to wrap some of my MyBehaviorEnums in a Mutex, then insert them into a HashMap. Without the Mutex, when I get items from the HashMap, I can easily pattern match for different MyBehaviorEnum values. But I'm not exactly sure how to do this kind of matching when the MyHeaviorEnum values are wrapped in a Mutex, or what an idiomatic approach might look like.
enum_dispatch = "0.3.7"
use core::convert::TryInto;
use enum_dispatch::enum_dispatch;
use std::sync::Mutex;
use std::collections::HashMap;
struct MyImplementorA {}
impl MyBehavior for MyImplementorA {
fn my_trait_method(&self) {}
}
struct MyImplementorB {}
impl MyBehavior for MyImplementorB {
fn my_trait_method(&self) {}
}
#[enum_dispatch]
enum MyBehaviorEnum {
MyImplementorA,
MyImplementorB,
}
#[enum_dispatch(MyBehaviorEnum)]
trait MyBehavior {
fn my_trait_method(&self);
}
fn main() {
//No Mutex wrapper
let a: MyBehaviorEnum = MyImplementorA {}.into();
let a2: MyBehaviorEnum = MyImplementorA {}.into();
let mut map = HashMap::new();
map.insert("First", a);
map.insert("Second", a2);
match map.get_mut("First"){
Some(MyBehaviorEnum::MyImplementorA(a_instance)) =>{
a_instance.my_trait_method();
}
_=>()
}
//Implementor enum values are wrapped in Mutex then inserted into HashMap
let a: MyBehaviorEnum = MyImplementorA {}.into();
let a2: MyBehaviorEnum = MyImplementorA {}.into();
let mut map = HashMap::new();
map.insert("First", Mutex::new(a));
map.insert("Second", Mutex::new(a2));
match map.get_mut("First"){
Some(mutex_impl_a)=>{
match Mutex::into_inner(mutex_impl_a){
Ok(MyBehaviorEnum::MyImplementorA(a_instance)) =>{
a_instance.my_trait_method();
}
_=>()
}
}
}
}
When working with the mutex wrapped values, use:
match map.get_mut("First"){
Some(mutex_impl_a)=>{
match &*mutex_impl_a.lock().unwrap(){
MyBehaviorEnum::MyImplementorA(a_instance)=>{
dbg!("got it!");
}
_=>()
}
}
_=>()
}
I'm writing a UEFI OS loader, and I use the system table provided by efi_main in the panic handler to print a string on the console. Currently, I'm using a global static variable and a helper function to access it like this:
static SYSTEM_TABLE_WRAPPER: Lazy<Spinlock<Option<SystemTable>>> =
Lazy::new(|| Spinlock::new(None));
#[panic_handler]
fn panic(i: &PanicInfo<'_>) -> ! {
// SAFETY: The existing lock is forgotten. There is no way to access the lock from the panic
// handler.
unsafe { unlock_system_table() }
error!("{}", i);
loop {
x86_64::instructions::hlt();
}
}
pub fn _print(args: fmt::Arguments<'_>) {
let mut st = crate::system_table();
let mut stdout = st.con_out();
let _ = stdout.write_fmt(args);
}
#[macro_export]
macro_rules! println {
() => {
$crate::print!("\n");
};
($($arg:tt)*)=>{
$crate::print!("{}\n",core::format_args!($($arg)*));
}
}
#[macro_export]
macro_rules! print {
($($arg:tt)*) => {
$crate::io::_print(core::format_args!($($arg)*));
};
}
pub(crate) fn system_table<'a>() -> MappedSpinlockGuard<'a, uefi_wrapper::SystemTable> {
let st = SYSTEM_TABLE_WRAPPER.try_lock();
let st = st.expect("Failed to lock the global System Table.");
SpinlockGuard::map(st, |st| {
let st = st.as_mut();
let st = st.expect("The global System Table is not initialized.");
&mut st.0
})
}
Although this works correctly, I'd like to avoid using any global variables if possible. Is there a way to do that?
I dont think so. If its possible, any parameter would be a global as well. Making it more complex.
Global variables are ok for this. Create your own global panic object and give it to a new panic handler from the real one.
Because there seems to be no way to do that, I changed the way.
Firstly, I defined the uefi_print and uefi_println macros.
#[macro_export]
macro_rules! uefi_print{
($st:expr,$($arg:tt)*)=>{
$crate::io::_print($st,format_args!($($arg)*));
}
}
#[macro_export]
macro_rules! uefi_println {
($st:expr) => {
$crate::uefi_print!($st,"\n");
};
($st:expr,$($arg:tt)*)=>{
$crate::uefi_print!($st,"{}\n",format_args!($($arg)*));
}
}
#[doc(hidden)]
pub fn _print(st: &mut crate::SystemTable, args: fmt::Arguments<'_>) {
let mut con_out = st.con_out();
let _ = con_out.write_fmt(args);
}
These macros are similar to print and println macros, but the first parameter is the mutable reference to SystemTable. The example macro invocation:
#[no_mangle]
pub extern "win64" fn efi_main(h: uefi_wrapper::Handle, mut st: bootx64::SystemTable) -> ! {
let resolution = gop::set_preferred_resolution(&mut st);
uefi_println!(&mut st, "GOP info: {:?}", resolution,);
// ...
}
Secondly, I defined the uefi_panic macro:
#[macro_export]
macro_rules! uefi_panic {
($st:expr) => {
$crate::uefi_panic!($st, "explicit panic");
};
($st:expr,$($t:tt)+)=>{
$crate::uefi_println!($st,"panicked at '{}', {}:{}:{}",core::format_args!($($t)+),file!(),line!(),column!());
panic!();
}
}
#[panic_handler]
fn panic(_: &PanicInfo<'_>) -> ! {
loop {
x86_64::instructions::hlt();
}
}
The first parameter of the macro is also the mutable reference to SystemTable.
Thirdly, I defined a wrapper type for SystemTable that defines the additional method expect_ok.
#[repr(transparent)]
#[derive(Debug)]
pub struct SystemTable(uefi_wrapper::SystemTable);
impl SystemTable {
// ...
/// # Panics
///
/// This method panics if `result` is [`Err`].
pub fn expect_ok<T, E: fmt::Debug>(&mut self, result: Result<T, E>, msg: &str) -> T {
match result {
Ok(val) => val,
Err(e) => {
uefi_panic!(self, "{}: {:?}", msg, e);
}
}
}
}
Now I prefer this way to the previous method. The exit boot services function can move the ownership of SystemTable and ImageHandle. This way prevents these types from being used after calling it. After all, I should not create a global static SystemTable since it won't be valid after exiting the boot services.
I am wrapping libxml2 in Rust as an exercise in learning the Rust FFI, and I have come across something strange. I am new to Rust, but I believe the following should work.
In main.rs I have:
mod xml;
fn main() {
if let doc = xml::parse_file("filename") {
doc.simple_function();
}
}
And xml.rs is:
extern create libc;
use libc::{c_void, c_char, c_int, c_ushort};
use std::ffi::CString;
// There are other struct definitions I've implemented that xmlDoc
// depends on, but I'm not going to list them because I believe
// they're irrelevant
#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
#[repr(C)]
struct xmlDoc {
// xmlDoc structure defined by the libxml2 API
}
pub struct Doc {
ptr: *mut xmlDoc
}
impl Doc {
pub fn simple_function(&self) {
if self.ptr.is_null() {
println!("ptr doesn't point to anything");
} else {
println!("ptr is not null");
}
}
}
#[allow(non_snake_case)]
#[link(name = "xml2")]
extern {
fn xmlParseFile(filename: *const c_char) -> *mut xmlDoc;
}
pub fn parse_file(filename: &str) -> Option<Doc> {
unsafe {
let result;
match CString::new(filename) {
Ok(f) => { result = xmlParseFile(f.as_ptr()); },
Err(_) => { return None; }
}
if result.is_null() {
return None;
}
Some(Doc { ptr: result })
}
}
I'm wrapping the C struct, xmlDoc in a nice Rust-friendly struct, Doc, to have a clear delineation between the safe (Rust) and unsafe (C) data types and functions.
This all works for the most part except when I compile, I get an error in main.rs:
src/main.rs:38:13: 38:28 error: no method named 'simple_function' found
for type 'std::option::Option<xml::Doc>' in the current scope
src/main.rs:38 doc.simple_function();
^~~~~~~~~~~~~~~
error: aborting due to previous error`
It seems convinced that doc is an Option<xml::Doc> even though I'm using the if let form that should unwrap the Option type. Is there something I'm doing incorrectly?
match xml::parse_file("filename") {
Some(doc) => doc.simple_function(),
None => {}
}
The above works fine, but I'd like to use the if let feature of Rust if I'm able.
You need to pass the actual pattern to if let (unlike languages like Swift which special case if let for Option types):
if let Some(doc) = xml::parse_file("filename") {
doc.simple_function();
}
I'm trying to parallelize an algorithm I have. This is a sketch of how I would write it in C++:
void thread_func(std::vector<int>& results, int threadid) {
results[threadid] = threadid;
}
std::vector<int> foo() {
std::vector<int> results(4);
for(int i = 0; i < 4; i++)
{
spawn_thread(thread_func, results, i);
}
join_threads();
return results;
}
The point here is that each thread has a reference to a shared, mutable object that it does not own. It seems like this is difficult to do in Rust. Should I try to cobble it together in terms of (and I'm guessing here) Mutex, Cell and &mut, or is there a better pattern I should follow?
The proper way is to use Arc<Mutex<...>> or, for example, Arc<RWLock<...>>. Arc is a shared ownership-based concurrency-safe pointer to immutable data, and Mutex/RWLock introduce synchronized internal mutability. Your code then would look like this:
use std::sync::{Arc, Mutex};
use std::thread;
fn thread_func(results: Arc<Mutex<Vec<i32>>>, thread_id: i32) {
let mut results = results.lock().unwrap();
results[thread_id as usize] = thread_id;
}
fn foo() -> Arc<Mutex<Vec<i32>>> {
let results = Arc::new(Mutex::new(vec![0; 4]));
let guards: Vec<_> = (0..4).map(|i| {
let results = results.clone();
thread::spawn(move || thread_func(results, i))
}).collect();
for guard in guards {
guard.join();
}
results
}
This unfortunately requires you to return Arc<Mutex<Vec<i32>>> from the function because there is no way to "unwrap" the value. An alternative is to clone the vector before returning.
However, using a crate like scoped_threadpool (whose approach could only be recently made sound; something like it will probably make into the standard library instead of the now deprecated thread::scoped() function, which is unsafe) it can be done in a much nicer way:
extern crate scoped_threadpool;
use scoped_threadpool::Pool;
fn thread_func(result: &mut i32, thread_id: i32) {
*result = thread_id;
}
fn foo() -> Vec<i32> {
let results = vec![0; 4];
let mut pool = Pool::new(4);
pool.scoped(|scope| {
for (i, e) in results.iter_mut().enumerate() {
scope.execute(move || thread_func(e, i as i32));
}
});
results
}
If your thread_func needs to access the whole vector, however, you can't get away without synchronization, so you would need a Mutex, and you would still get the unwrapping problem:
extern crate scoped_threadpool;
use std::sync::Mutex;
use scoped_threadpool::Pool;
fn thread_func(results: &Mutex<Vec<u32>>, thread_id: i32) {
let mut results = results.lock().unwrap();
result[thread_id as usize] = thread_id;
}
fn foo() -> Vec<i32> {
let results = Mutex::new(vec![0; 4]);
let mut pool = Pool::new(4);
pool.scoped(|scope| {
for i in 0..4 {
scope.execute(move || thread_func(&results, i));
}
});
results.lock().unwrap().clone()
}
But at least you don't need any Arcs here. Also execute() method is unsafe if you use stable compiler because it does not have a corresponding fix to make it safe. It is safe on all compiler versions greater than 1.4.0, according to its build script.