I have an enum with multiple single field tuple struct variants. Each tuple struct field is a different struct. I tried this code:
struct Foo { a: i32 }
struct Bar { b: i32 }
enum Foobar {
Foo(Foo),
Bar(Bar)
}
impl Foobar {
fn new_foo() -> Foobar {
Foobar::Foo(Foo { a: 1 })
}
fn new_bar() -> Foobar {
Foobar::Bar(Bar { b: 2 })
}
}
fn main() {
let x = vec![Foobar::new_foo(), Foobar::new_bar()];
let mut i = 0;
while i < x.len() {
let element = &x[i];
match element {
&Foobar::Foo(_) => { x[i].a = 3 },
&Foobar::Bar(_) => { x[i].b = 4 }
}
i += 1
}
}
The compiler says:
error: attempted access of field a on type Foobar, but no field with that name was found
I tried the solution found in this question but it says:
error: cannot borrow immutable anonymous field as mutable
How can I modify the fields of the content of vector x?
This is because your vector and the reference element are immutable. Try this:
fn main() {
let mut x = vec![Foobar::new_foo(), Foobar::new_bar()];
let mut i = 0;
while i < x.len() {
let element = &mut x[i];
match *element {
Foobar::Foo(Foo { ref mut a }) => { *a = 3 },
Foobar::Bar(Bar { ref mut b }) => { *b = 4 }
}
i += 1
}
}
Related
I implement a lockfree ringbuffer, and then i test for debug is ok, but in release mode it can't work allways.
use std::path::Display;
use std::sync::Arc;
#[derive(Debug)]
pub struct RingBuffer<T, const m_size: usize> {
idx_head: usize,
idx_tail: usize,
m_data: [T; m_size],
}
pub trait Queue<T> {
fn new_empty() -> Self;
fn push(&mut self, value: T) -> bool;
fn pop(&mut self) -> Option<&T>;
fn is_full(&self) -> bool;
fn is_empty(&self) -> bool;
}
impl<T, const Size: usize> Queue<T> for RingBuffer<T, Size>
{
fn new_empty() -> Self {
RingBuffer::<T, Size> {
idx_head: 0,
idx_tail: 0,
m_data: array_init::array_init(|_| {
unsafe {
std::mem::zeroed()
}
}),
}
}
fn push(&mut self, value: T) -> bool {
let mut head = self.idx_head + 1;
if head == Size {
head = 0;
}
if head == self.idx_tail {
return false;
}
self.m_data[self.idx_head] = value;
self.idx_head = head;
return true;
}
fn pop(&mut self) -> Option<&T> {
let mut tail = self.idx_tail;
if self.idx_head == tail {
return None;
}
let res = &self.m_data[tail];
tail += 1;
if tail == Size {
tail = 0;
}
self.idx_tail = tail;
return Some(res);
}
fn is_full(&self) -> bool {
self.idx_tail == (self.idx_head + 1) % Size
}
fn is_empty(&self) -> bool {
self.idx_head == self.idx_tail
}
}
pub struct SharedRingBuffer<T, const m_size: usize> {
pub ringbuffer: Arc<RingBuffer<T, m_size>>,
}
impl<T, const Size: usize> Clone for SharedRingBuffer<T, Size> {
fn clone(&self) -> Self {
Self {
ringbuffer: self.ringbuffer.clone(),
}
}
}
impl<T, const Size: usize, > Queue<T> for SharedRingBuffer<T, Size> {
fn new_empty() -> Self {
Self {
ringbuffer: Arc::new(RingBuffer::<T, Size>::new_empty()),
}
}
fn push(&mut self, value: T) -> bool {
unsafe {
(*Arc::get_mut_unchecked(&mut self.ringbuffer)).push(value)
}
}
fn pop(&mut self) -> Option<&T> {
unsafe {
(*Arc::get_mut_unchecked(&mut self.ringbuffer)).pop()
}
}
fn is_full(&self) -> bool {
self.ringbuffer.is_full()
}
fn is_empty(&self) -> bool {
self.ringbuffer.is_empty()
}
}
////////////////////// for test//////////////////////////
fn test_speed1() {
let mut q: SharedRingBuffer<i32, 8> = SharedRingBuffer::new_empty();
let mut t0 = std::time::SystemTime::now();
let t = {
let mut q = q.clone();
std::thread::spawn(move || {
loop {
let t = match q.pop() {
None => {
// std::thread::sleep(Duration::from_millis(10));
continue;
}
Some(res) => res
};
if *t == -1 {
break;
}
std::thread::sleep(Duration::from_millis(1));
}
let now = std::time::SystemTime::now();
println!("res: {}", now.duration_since(t0).unwrap().as_millis());
})
};
for i in 0..99 {
loop {
if q.push(i) {
// std::thread::sleep(Duration::from_millis(10));
break;
}
}
}
q.push(-1);
t.join().unwrap();
}
When i addition std::thread::sleep(Duration::from_millis(10)) for q.push and q.pop method it is work well.
rustc 1.67.0-nightly (95a3a7277 2022-10-31)
binary: rustc
commit-hash: 95a3a7277b44bbd2dd3485703d9a05f64652b60e
commit-date: 2022-10-31
host: x86_64-pc-windows-msvc
release: 1.67.0-nightly
LLVM version: 15.0.4
I expect the RingBuffer can work well.
The equivalent code is:
fn test_speed2() {
let (send, recv) = channel::<i32>();
let mut is_run = SharedValue::new(true);
let mut t0 = std::time::SystemTime::now();
let t = {
let is_run = is_run.clone();
std::thread::spawn(move || {
loop {
let t = match recv.recv() {
Err(e) => {
break;
}
Ok(res) => res
};
if t == -1 {
break;
}
std::thread::sleep(Duration::from_millis(1));
}
let now = std::time::SystemTime::now();
// println!("res: {}", now.duration_since(t0).unwrap().as_millis());
})
};
for i in 0..99 {
send.send(i).unwrap();
}
send.send(-1).unwrap();
t.join().unwrap();
}
I hope ringbuffer can replace channel to communicate between two threads,Because ringbuffer is lockfree and faster.
Your code causes undefined behavior by creating two mutable references to the same object at the same time via Arc::get_mut_unchecked(). It looks like this was even your intention, but it is blatantly violating Rust's rules. Even when using unsafe, you cannot violate the requirement that mutable references are exclusive.
Running your code with cargo miri reports this undefined behavior:
error: Undefined Behavior: Data race detected between Read on thread `<unnamed>` and Write on thread `main` at alloc1894+0x10
--> bar/src/main.rs:45:12
|
45 | if self.idx_head == tail {
| ^^^^^^^^^^^^^ Data race detected between Read on thread `<unnamed>` and Write on thread `main` at alloc1894+0x10
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `<RingBuffer<i32, 8> as Queue<i32>>::pop` at bar/src/main.rs:45:12
note: inside `<SharedRingBuffer<i32, 8> as Queue<i32>>::pop` at bar/src/main.rs:89:18
--> bar/src/main.rs:89:18
|
89 | unsafe { (*Arc::get_mut_unchecked(&mut self.ringbuffer)).pop() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside closure at bar/src/main.rs:108:31
--> bar/src/main.rs:108:31
|
108 | let t = match q.pop() {
| ^^^^^^^
You will need to rethink your design. You'll probably need a foundation like this to make it safe to modify between threads:
use std::cell::UnsafeCell;
use std::mem::MaybeUninit;
use std::sync::atomic::AtomicUsize;
pub struct RingBuffer<T, const SIZE: usize> {
idx_head: AtomicUsize,
idx_tail: AtomicUsize,
m_data: [UnsafeCell<MaybeUninit<T>>; SIZE],
}
This is actually caused by the CPU cache,The solution is as follows:
fn push(&mut self, value: T) -> bool {
let mut head = unsafe {
std::ptr::read_volatile(&self.idx_head) + 1
};
let tail = unsafe {
std::ptr::read_volatile(&self.idx_tail)
};
if head == Size {
head = 0;
}
if head == tail {
return false;
}
self.m_data[self.idx_head] = value;
unsafe {
std::ptr::write_volatile(&mut self.idx_head, head);
}
return true;
}
fn pop(&mut self) -> Option<&T> {
let mut tail = unsafe {
std::ptr::read_volatile(&self.idx_tail)
};
let head = unsafe {
std::ptr::read_volatile(&self.idx_head)
};
if head == tail {
return None;
}
let res = &self.m_data[tail];
tail += 1;
if tail == Size {
tail = 0;
}
unsafe {
std::ptr::write_volatile(&mut self.idx_tail, tail);
}
return Some(res);
}
I want to iterate two nested vectors (Playground):
struct Name {
index: usize,
data: Vec<String>,
}
impl Name {
fn new(test: bool) -> Option<Name> {
if test {
Some(Name {
index: 0,
data: vec![String::from("ATGCTA"), String::from("ACGTGA")],
})
} else {
None
}
}
fn iter_record(&mut self) -> Option<&[u8]> {
self.index += 1;
if self.index < self.data.len() {
Some(self.data[self.index - 1].as_bytes())
} else {
None
}
}
}
struct Data {
index: usize,
data: Vec<Option<Name>>,
}
impl Data {
fn new() -> Data {
Data {
index: 0,
data: vec![Name::new(true)],
}
}
fn iter_record(&mut self) -> Option<&[u8]> {
let max_index = self.data.len() - 1;
let record = self.data[self.index].as_mut().unwrap().iter_record();
match record {
None => {
if self.index < max_index {
self.index += 1;
return self.iter_record();
}
}
_ => {}
}
record
}
}
fn main() {
let mut data = Data::new();
while let Some(ret) = data.iter_record() {
println!("{:?}", ret);
}
}
Here is the build error:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:47:28
|
40 | fn iter_record(&mut self) -> Option<&[u8]> {
| - let's call the lifetime of this reference `'1`
41 | let max_index = self.data.len() - 1;
42 | let record = self.data[self.index].as_mut().unwrap().iter_record();
| --------- first mutable borrow occurs here
...
47 | return self.iter_record();
| ^^^^ second mutable borrow occurs here
...
52 | record
| ------ returning this value requires that `self.data` is borrowed for `'1`
Why does this error occur? How do I solve it?
The issue is that some parts of the NLL were not implemented in the compiler, because they are too CPU intensive. As a result the compiler cannot recognize that the borrow does not extend outside of the match. In the general case the workaround is to wrap it in an if statement that unconditionally returns. The downside is that the code would be slower at runtime, because it would need to do the same check twice. This mechanism is much better explained in the linked document.
fn iter_record(&mut self) -> Option<&[u8]> {
let max_index = self.data.len() - 1;
// This will not really work in your case, because you are modifying the struct's state, thus each method invocation will produce a different result
let check = self.data[self.index].as_mut().unwrap().iter_record();
if check.is_some() {
match self.data[self.index].as_mut().unwrap().iter_record() {
Some(r) => return Some(r),
None => unreachable!(),
}
}
if self.index < max_index {
self.index += 1;
return self.iter_record();
}
None
}
Unfortunately in your case this will not work, because your Name::iter_record() modifies the internal state of the structure, thus it's not possible to call it twice. In order to resolve that issue I'll introduce a new method peek_record() which will just return true or false depending on whether iter_record() would have returned Some or None if called instead:
fn peek_record(&self) -> bool {
self.index + 1 < self.data.len()
}
This would result in the following working code:
struct Name {
index: usize,
data: Vec<String>,
}
impl Name {
fn new(test: bool) -> Option<Name> {
if test {
Some(Name {
index: 0,
data: vec![String::from("ATGCTA"), String::from("ACGTGA")],
})
} else {
None
}
}
fn iter_record(&mut self) -> Option<&[u8]> {
self.index += 1;
if self.index < self.data.len() {
Some(self.data[self.index - 1].as_bytes())
} else {
None
}
}
fn peek_record(&self) -> bool {
self.index + 1 < self.data.len()
}
}
struct Data {
index: usize,
data: Vec<Option<Name>>,
}
impl Data {
fn new() -> Data {
Data {
index: 0,
data: vec![Name::new(true)],
}
}
fn iter_record(&mut self) -> Option<&[u8]> {
let max_index = self.data.len() - 1;
if self.data[self.index].as_mut().unwrap().peek_record() {
match self.data[self.index].as_mut().unwrap().iter_record() {
Some(r) => return Some(r),
None => unreachable!(),
}
}
if self.index < max_index {
self.index += 1;
return self.iter_record();
}
None
}
}
fn main() {
let mut data = Data::new();
while let Some(ret) = data.iter_record() {
println!("{:?}", ret);
}
}
PS: You can further simplify your code by getting rid of the recursion:
fn iter_record(&mut self) -> Option<&[u8]> {
for idx in self.index..self.data.len() {
if self.data[idx].as_mut().unwrap().peek_record() {
match self.data[idx].as_mut().unwrap().iter_record() {
Some(r) => return Some(r),
None => unreachable!(),
}
}
self.index += 1;
}
None
}
I'd like to match enums that have struct values. When I'm doing matching an enum, it seems I'm required to provide a value for the Enum field if it has one.
I'd like to set this value to A::default(), and reference the values of this default, but that gives me the error: expected tuple struct or tuple variant, found associated function `A::default. How can I work around this? Playground
use std::default::Default;
struct A {
val_1: i32,
val_2: i32,
val_3: Vec<String>,
}
impl Default for A {
fn default() -> A {
A {
val_1: 0,
val_2: 0,
val_3: vec!["Hello".to_string()],
}
}
}
struct B {
val_1: i32,
val_2: i32,
val_3: A,
}
impl Default for B {
fn default() -> B {
B {
val_1: 0,
val_2: 0,
val_3: A::default(),
}
}
}
enum Ops {
OpA { config: A },
OpB { config: B },
}
struct Mast {
pub OpType: Ops,
}
fn main() {
let myop = Mast {
OpType: Ops::OpA {
config: A::default(),
},
};
match myop.OpType {
Ops::OpA{ config: A::default() } => {
println!("{}", "got OpA"),
println!("{}", A::default().val_1),
}//<--'expected tuple struct or tuple variant, found associated function `A::default`'
Ops::OpB{ config: B::default() } => println!("{}", "got OpB"),
}
}
You don't care about the struct field value, so use .. to ignore the value:
match myop.OpType {
Ops::OpA {..} => println!("{}", "got OpA"),
Ops::OpB {..} => println!("{}", "got OpA"),
}
If you want to extract the config field into a variable, let's say foo, then you can do this:
match myop.OpType {
Ops::OpA {config: foo} => println!("OpA: {}", foo),
Ops::OpB {config: foo} => println!("OpB: {}", foo),
}
This is also why your old code doesn't work: because pattern matching extracts patterns into variables, and it does not check values for equality.
If you want to mutate it, then match it by ref:
match myop.OpType {
Ops::OpA {config: ref mut foo} => *foo = A::default(),
Ops::OpB {config: ref mut foo} => *foo = B::default(),
}
This will require myop to be mut as well. There's also a shorthand, {config}, which will expand to {config: config}:
match myop.OpType {
Ops::OpA {ref mut config} => *config = A::default(),
Ops::OpB {ref mut config} => *config = B::default(),
}
See also:
The Rust Language: Pattern Syntax
The Rust Reference: Patterns
I have a vector of structs, and I'm comparing every element in the vector against every other element, and in certain cases mutating the current element.
My issue is that you can't have both a mutable and immutable borrow happening at the same time, but I'm not sure how to reframe my problem to get around this without cloning either the current element or the entire vector, which seems like a waste since I'm only ever mutating the current element, and it doesn't need to be compared to itself (I skip that case).
I'm sure there's an idiomatic way to do this in Rust.
struct MyStruct {
a: i32,
}
fn main() {
let mut v = vec![MyStruct { a: 1 }, MyStruct { a: 2 }, MyStruct { a: 3 }];
for elem in v.iter_mut() {
for other_elem in v.iter() {
if other_elem.a > elem.a {
elem.a += 1;
}
}
}
}
The simplest way is to just use indices, which don't involve any long-lived borrows:
for i in 0..v.len() {
for j in 0..v.len() {
if i == j { continue; }
if v[j].a > v[i].a {
v[i].a += 1;
}
}
}
If you really, really want to use iterators, you can do it by dividing up the Vec into disjoint slices:
fn process(elem: &mut MyStruct, other: &MyStruct) {
if other.a > elem.a {
elem.a += 1;
}
}
for i in 0..v.len() {
let (left, mid_right) = v.split_at_mut(i);
let (mid, right) = mid_right.split_at_mut(1);
let elem = &mut mid[0];
for other in left {
process(elem, other);
}
for other in right {
process(elem, other);
}
}
If you can modify type type of v, and the elements of v are Copy, you can wrap MyStruct in Cell.
#[derive(Copy, Clone)]
struct MyStruct {
a: i32,
}
fn main() {
use std::cell::Cell;
let v = vec![
Cell::new(MyStruct { a: 1 }),
Cell::new(MyStruct { a: 2 }),
Cell::new(MyStruct { a: 3 }),
];
for elem in v.iter() {
for other_elem in v.iter() {
let mut e = elem.get();
if other_elem.get().a > e.a {
e.a += 1;
elem.set(e);
}
}
}
}
If instead you're passed a &mut to a slice (or &mut that can be converted into a slice), use Cell::from_mut and Cell::as_slice_of_cells and use the same trick as above (assuming the elements of the slice are Copy).
I want to keep an Holded instance, but I can't since it's in an array. How can I do to 'extract' this instance from the array and keep it in an Object instance ? (In my original code, I don't have array but iterators). Here is the equivalent code :
struct Holded {
value: u8,
}
struct Holder;
impl Holder {
pub fn get(&self) -> [Holded; 2] {
[Holded { value: 0 }, Holded { value: 1 }]
}
}
struct Object<'a> {
holded: &'a Holded,
}
fn main() {
let holder = Holder;
let obj = work(&holder).unwrap();
println!("{}", obj.holded.value);
}
fn work(holder: &Holder) -> Option<Object> {
let mut obj: Object;
let array = holder.get();
for h in array.into_iter() {
if h.value == 1u8 {
obj = Object { holded: h };
return Some(obj);
}
}
None
}
The error message:
error: `array` does not live long enough
--> src/main.rs:28:14
|
28 | for h in array.into_iter() {
| ^^^^^ does not live long enough
...
36 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the block at 24:43...
--> src/main.rs:24:44
|
24 | fn work(holder: &Holder) -> Option<Object> {
| ^
In the MCVE you have posted, the struct Object contains a reference to Holded:
struct Object<'a> {
holded: &'a Holded,
}
In the function work() you return an Object (optionally):
fn work(holder: &Holder) -> Option<Object> {
You acquire Holded from a function which returns it by value:
impl Holder {
pub fn get( &self ) -> [Holded; 2] {
[Holded { value: 0 }, Holded { value: 1 }]
}
}
Now this will never work. If you return a reference to Holded, the Holded you reference to, must be stored somewhere. This means either as an input, or as an output of the function work().
I rewrote your example to include Holded inside Holder. That is one way to solve this. But I am not sure this would apply to your original problem.
struct Holded {
value: u8,
}
struct Holder{
value: [Holded; 2],
}
impl Holder {
pub fn new() -> Holder {
Holder {value: [Holded { value: 0 }, Holded { value: 1 }] }
}
pub fn get( &self ) -> &[Holded; 2] {
&self.value
}
}
struct Object<'a> {
holded: &'a Holded,
}
fn main() {
let holder = Holder::new();
let obj = work(&holder).unwrap();
println!("{}", obj.holded.value);
let obj = work2(&holder).unwrap();
println!("{}", obj.holded.value);
}
fn work(holder: &Holder) -> Option<Object> {
let obj: Object;
let array = holder.get();
for h in array.into_iter() {
if h.value == 1u8 {
obj = Object { holded: h };
return Some(obj);
}
}
None
}
fn work2(holder: &Holder) -> Option<Object> {
holder.get()
.iter()
.filter(|h| h.value == 1u8)
.map(|h| Object { holded: h })
.next()
}
You notice I also added a different way to implement the work() function (work2()).