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