Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non-mut peek? #12

Open
daschl opened this issue Jun 7, 2016 · 4 comments
Open

Non-mut peek? #12

daschl opened this issue Jun 7, 2016 · 4 comments

Comments

@daschl
Copy link

daschl commented Jun 7, 2016

Hi folks,

I've been poking around in data structures and I need to remove an element from this linked list (it stores a reference of a trait). My code is basically:

pub fn remove(&mut self, timer: &'a T) {
  // other stuff.
        let mut cursor = list.cursor();

        loop {
            let next = cursor.peek_next();
            if next.is_some() {
                if *(next.unwrap()) as *const T == timer as *const T {
                    cursor.remove();
                    break;
                }
                cursor.seek_forward(1);
            } else {
                break;
            }
        }
}

Now this doesn't work because remove and/or seek_forward borrow mut, but the peek_next did already. I think in this case what I'd need would be a peek which doesn't return a mut, right? Can we put that in or is there an obvious solution that I don't know about?

@gankro wdyt?

@daschl
Copy link
Author

daschl commented Jun 7, 2016

I think I was able to work around it by doing

        let pos = list.iter()
            .position(|t| *t as *const T == timer as *const T)
            .expect("Position not found!");
        list.remove(pos);

But if I'm not mistaken that in the worst case involves 2 full seeks instead of 1 so its O(2n), right?

@apasel422
Copy link
Contributor

You can't call Cursor::remove or Cursor::seek_forward while the borrow from Cursor::peek_next is outstanding, regardless of whether peek_next returns &T or &mut T. You can get around this by restructuring the scopes in your code:

enum Action {
    Remove,
    SeekForward,
}

loop {
    let action = match cursor.peek_next() {
        Some(t) =>
            if *t as *const T == timer as *const T {
                Action::Remove
            } else {
                Action::SeekForward
            },
        None => break,
    };

    match action {
        Action::Remove => {
            cursor.remove();
            break;
        }
        Action::SeekForward => cursor.seek_forward(1),
    }
}

@daschl
Copy link
Author

daschl commented Jun 7, 2016

@apasel422 would it make sense to add a remove method to it?

And thanks for the example clarification!

@nitnelave
Copy link

I think you can simply do this:

loop {
    let should_unwrap = cursor.peek_next().is_some();
    if should_unwrap {
        if *(next.unwrap()) as *const T == timer as *const T {
            cursor.remove();
            break;
        }
        cursor.seek_forward(1);
    } else {
        break;
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants