When implementing a skip list in Rust, I got stuck when trying to implement Iterator
for a Rc<RefCell<T>>
chain.
pub struct SkipList<K, V> {
head: Rc<RefCell<SkipNode<K, V>>>,
rng: rand::rngs::ThreadRng,
len: usize,
}
impl<K: Ord, V> SkipList<K, V> {
pub fn iter(&self) -> Iter<K, V> {
let next = &RefCell::borrow(&self.head).next_by_height[0];
Iter {
ptr: next.as_ref().map(|ref cell|Rc::clone(cell)),
_marker: Default::default(),
}
}
}
struct SkipNode<K, V> {
entry: Entry<K, V>,
next_by_height: [Option<Rc<RefCell<SkipNode>>>; MAX_HEIGHT],
}
pub struct Entry<K, V> {
key: K,
value: V,
}
struct SkipNode<K, V> {
entry: Option<Entry<K, V>>,
next_by_height: SkipTrack<K, V>,
}
pub struct Iter<'a, K: Ord, V> {
ptr: Option<Rc<RefCell<SkipNode<K, V>>>>,
_marker: marker::PhantomData<&'a K>,
}
impl<'a, K, V: 'a> Iterator for Iter<'a, K, V>
where K: Ord
{
type Item = Ref<'a, Entry<K, V>>;
fn next(&mut self) -> Option<Self::Item> {
self.ptr.take().map(|node| {
let current = RefCell::borrow(&node);
self.ptr = current.next_by_height[0].as_ref().map(|ref node| Rc::clone(node));
Ref::map(current, |ref wrapped| {
&wrapped.entry.unwrap()
})
})
}
}
and the error is:
Compiling RclessRefCelllessTgreatergreater-Rust v0.1.0 (/home/runner/RclessRefCelllessTgreatergreater-Rust)
error[E0515]: cannot return reference to temporary value
--> main.rs:138:15
|
138 | &wrapped.entry.unwrap()
| ^----------------------
| ||
| |temporary value created here
| returns a reference to data owned by the current function
error[E0507]: cannot move out of `wrapped.entry` which is behind a shared reference
--> main.rs:138:16
|
138 | &wrapped.entry.unwrap()
| ^^^^^^^^^^^^^
| |
| move occurs because `wrapped.entry` has type `std::option::Option<Entry<K, V>>`, which does not implement the `Copy` trait
| help: consider borrowing the `Option`'s content: `wrapped.entry.as_ref()`
error[E0515]: cannot return value referencing function parameter `node`
--> main.rs:137:13
|
135 | let current = RefCell::borrow(&node);
| ----- `node` is borrowed here
136 | self.ptr = current.next_by_height[0].as_ref().map(|ref node| Rc::clone(node));
137 | / Ref::map(current, |ref wrapped| {
138 | | &wrapped.entry.unwrap()
139 | | })
| |______________^ returns a value referencing data owned by the current function
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0507, E0515.
For more information about an error, try `rustc --explain E0507`.
error: could not compile `RclessRefCelllessTgreatergreater-Rust`.
the full code is available at Repl.it.
I attempted to take the Ref<T>
as the Item
returned by Iterator
, but the compiler complained that next
could not return a temporary variable. Is there an elegant way to implement Iterator
for Rc<RefCell>
?