Skip to content

Tracking Issue for vec::Drain{,Filter}::keep_rest #101122

Description

Feature gate: #![feature(drain_keep_rest)]

This is a tracking issue for vec::Drain{,Filter}::keep_rest, methods allowing to keep elements in a Vec after draining some of them.

Public API

// mod alloc::vec

impl<T, A: Allocator> Drain<'_, T, A> {
    pub fn keep_rest(self);
}

impl<T, F, A: Allocator> DrainFilter<'_, T, F, A>
where
    F: FnMut(&mut T) -> bool,
{
    pub fn keep_rest(self);
}

Steps / History

Unresolved Questions

  • Just change the not-yet-stable Drop for DrainFilter to keep rest?
    • Advantage: usually what you want (??)
      • e.g. .drain_filter(f).take(N) works as expected
    • Disadvantage: inconsistent with stable Drop for Drain
    • If you want to remove rest (matching the current unstable behavior of drain_filter) then you'd need to write .foreach(drop) to explicitly drop all the rest of the range that matches the filter.
  • &mut self instead of self?
    • If you're holding a Drain inside a struct and are operating on it from a &mut self method of the struct, keep_rest(self) is impossible to use. :(
      • You'd want something like mem::replace(&mut self.drain_filter, Vec::new().drain(..)).keep_rest() but the borrow checker won't like that.
      • Failing that, you'd need to change your Drain field to Option<Drain> and use self.drain_filter.take().unwrap().keep_rest() along with unwrap() everywhere else that the drain is used. Not good.
    • We'd need to define behavior of calling .next() after .keep_rest(). Presumably one of:
      • .next() returns None
      • this is considered incorrect usage and so .next() panic!s
      • .keep_rest() sets a flag inside the Drain which Drop will use to decide its behavior, and you're free to continue accessing iterator elements in between.
    • Another alternative: add a const EXHAUST_ON_DROP: bool = true const generic parameter
      • It's still impossible to set the flag without ownership
      • You can store &mut Drain<'a, T, A, false> from the beginning
      • Works better with iterator APIs, i.e.
        vec.drain_filter(f).keeping_rest().take(N).for_each(g);
        Instead of
        let mut iter = vec.drain_filter(f);
        iter.by_ref().take(N).for_each(g);
        iter.keep_rest()

Footnotes

  1. https://std-dev-guide.rust-lang.org/feature-lifecycle/stabilization.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    C-tracking-issueCategory: A tracking issue for an RFC or an unstable feature.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions