There may be another way, but one safe option is to use util::replace
to always set the `root` field to None but preserve the old value, as
shown below (this code compiles).

In general, the rule you are running into (which prevents mutation to
the path that contains a borrowed &mut) is one that I have gone back
and forth on. I have to go consult my notes as to the reason it is
setup the way it is; it may be that we could potentially loosen the
rule in this case, but I seem to recall that doing so had dangerous
consequences that I cannot remember at the moment.

> /// Iterate and mutate on a tree map in an arbitrary order.
> impl<'self, T> Iterator<(&'self Path, &'self mut T)> for
> TreeMapMutIterator<'self, T> {
>     /// Move to the next value contained in the tree map.
>     fn next(&mut self) -> Option<(&'self Path, &'self mut T)> {
>         if self.levels.len() == 0 {
>             None
>         } else {
>             let last = self.levels.len() - 1;
>             let root = util::replace(&mut self.levels[last].root, None);
>             match root {
>                 Some(&ref mut entry) => {
>                     let path = &entry.path;
>                     let value = &mut entry.value;
>                     Some((path, value))
>                 }
>                 None => {
>                     match self.levels[last].iterator.next() {
>                         Some((_atom, treemap)) => {
>                             self.levels.push(fail!());
>                         }
>                         None => {
>                             self.levels.pop();
>                         }
>                     }
>                     self.next()
>                 }
>             }
>         }
>     }
> }


Niko


On Tue, Aug 20, 2013 at 05:50:31PM +0300, Oren Ben-Kiki wrote:
> Here is the heart of the code, maybe it will be clearer why I had to use
> unsafe (or, maybe, how I could avoid it):
> 
> /// A path is just an array of atoms.
> #[deriving(Eq, TotalEq, Ord, TotalOrd, Clone, IterBytes)]
> pub struct Path {
>     /// The array of atoms the path consists of.
>     pub atoms: ~[Atom],
> }
> 
> /// An entry contained in the tree map.
> #[deriving(Eq, TotalEq, Ord, TotalOrd)]
> pub struct TreeMapEntry<T> {
>     /// The full path of the entry.
>     path: Path,
> 
>     /// The value of the entry.
>     value: T,
> }
> 
> /// A tree map holds values of some arbitrary type, indexed by a path.
> pub struct TreeMap<T> {
>     /// The entry of this node, if any.
>     priv entry: Option<TreeMapEntry<T>>,
> 
>     /// The sub-trees under this node, if any.
>     priv sub_trees: HashMap<Atom, ~TreeMap<T>>
> }
> 
> /// Iterate and mutate on a single level of the tree map.
> struct LevelMutIterator<'self, T> {
>     /// The root node to return the value of (as the 1st result).
>     root: Option<&'self mut TreeMapEntry<T>>,
> 
>     /// The iterator at the current level of the tree.
>     iterator: HashMapMutIterator<'self, Atom, ~TreeMap<T>>,
> }
> 
> /// Iterate and mutate on a tree map in an arbitrary order.
> pub struct TreeMapMutIterator<'self, T> {
>     /// The iterators of all levels we have reached so far.
>     priv levels: ~[LevelMutIterator<'self, T>]
> }
> 
> /// Iterate and mutate on a tree map in an arbitrary order.
> impl<'self, T> Iterator<(&'self Path, &'self mut T)> for
> TreeMapMutIterator<'self, T> {
>     /// Move to the next value contained in the tree map.
>     fn next(&mut self) -> Option<(&'self Path, &'self mut T)> {
>         if self.levels.len() == 0 {
>             None
>         } else {
>             unsafe {
>                 let last: *mut LevelMutIterator<'self, T> = &mut
> self.levels[self.levels.len() - 1];
>                 match (*last).root {
>                     Some(ref mut entry) => {
>                         let path = &entry.path;
>                         let value = &mut entry.value;
>                         // TRICKY: This makes the entry inaccessible, which
> is
>                         // why we took the returned path and value above.
>                         (*last).root = None;
>                         Some((path, value))
>                     }
>                     None => {
>                         match self.levels[self.levels.len() -
> 1].iterator.next() {
>                             Some((_atom, treemap)) => {
>                                 self.levels.push(treemap.level_mut_iter());
>                             }
>                             None => {
>                                 self.levels.pop();
>                             }
>                         }
>                         self.next()
>                     }
>                 }
>             }
>         }
>     }
> }
> 
> I tried for around a day to make this work without the unsafe, to no avail.
> The trick is I want to take the value out of the option (leaving None
> behind), and return the value. I'm probably missing some solution which may
> be obvious to a non-newbie to Rust...?

> _______________________________________________
> Rust-dev mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/rust-dev

_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to