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 PriorityQueue
s 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 BinaryHeap
s, 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
while
loop? It seems likeself.active_filters
is borrowed twice. Even stranger,self: &mut
,ref_f: &Filter
, andmut f: Filter
are all alive at once. How is rustc happy with this?