Hi, I'm working through some little projects to help me learn Rust. Currently I'm working on a prime number sieve (implementation here). This is a Sieve of Eratosthenes, using some ideas from Melissa O'Neil's JFP paper.
I'm a little stuck on something, hoping to get some advice to get unstuck. ![]()
After the small primes (2, 3, 5, 7), I have a struct to help me walk through "bigger primes":
struct BiggerPrimes {
state: Wheel,
active_filters: PriorityQueue<Filter, Reverse<u64>>,
queued_filters: VecDeque<Filter>,
}
For my current question, the Wheel and VecDeque stuff isn't important -- all of that is working fine. But PriorityQueues are giving me some grief.
Filter looks like this:
#[derive(Hash, Copy, Clone, Eq, PartialEq)]
struct Filter {
base: u64,
state: u64,
}
The idea is that each base is a prime, and state steps through multiples of that prime.
Then BiggerPrimes has a method
fn step(&mut self) -> Option<u64>
that includes this loop:
while let Some((ref_f, _)) = self.active_filters.peek() {
match ref_f.state {
x if x < n => {
let mut f = self.active_filters.pop().unwrap().0;
f.state += f.base;
self.active_filters.push(f, Reverse(f.state));
}
x if x == n => {
return None;
}
_ => {
break;
}
}
}
Here ref_f: &Filter and f: Filter. Note that unlike BinaryHeaps, a PriorityQueue takes the item and priority separately as arguments.
The code works fine as is, but it's much slower than the BinaryHeap implementation. But currently I'm popping the queue, updating f, and then pushing it back on. I'd guess it could be more efficient to use PriorityQueue::change_priority, which has this spec:
pub fn change_priority<Q>(&mut self, item: &Q, new_priority: P) -> Option<P>
So my first twentieth or so attempt is
let fs = &mut self.active_filters;
while let Some((ref_f, _)) = fs.peek_mut() {
match ref_f.state {
x if x < n => {
ref_f.state += ref_f.base;
fs.change_priority(ref_f, Reverse(ref_f.state));
}
x if x == n => {
return None;
}
_ => {
break;
}
}
}
This doesn't work:
1 error[E0499]: cannot borrow `*fs` as mutable more than once at a time
--> src/main.rs:106:21
|
103 | while let Some((ref_f, _)) = fs.peek_mut() {
| -- first mutable borrow occurs here
...
106 | fs.change_priority(ref_f, Reverse(ref_f.state));
| ^^ ----- first borrow later used here
| |
| second mutable borrow occurs here
For more information about this error, try `rustc --explain E0499`.
error: could not compile `prime-sieve` (bin "prime-sieve") due to previous error
Sorry this is so long, but my questions are
- How can I fix this?
- Why is the compiler happy with the current
whileloop? It seems likeself.active_filtersis borrowed twice. Even stranger,self: &mut,ref_f: &Filter, andmut f: Filterare all alive at once. How is rustc happy with this?