mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-19 19:08:08 +00:00
index: add peekable RevWalk adapter
This helps to migrate union/intersection/difference iterators to RevWalk.
This commit is contained in:
parent
8f0b9a0e4a
commit
cfa067a0a9
1 changed files with 78 additions and 1 deletions
|
@ -39,6 +39,17 @@ pub(super) trait RevWalk<I: ?Sized> {
|
|||
// The following methods are provided for convenience. They are not supposed
|
||||
// to be reimplemented.
|
||||
|
||||
/// Wraps in adapter that can peek one more item without consuming.
|
||||
fn peekable(self) -> PeekableRevWalk<I, Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
PeekableRevWalk {
|
||||
walk: self,
|
||||
peeked: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reattaches the underlying `index`.
|
||||
fn attach(self, index: &I) -> RevWalkBorrowedIndexIter<'_, I, Self>
|
||||
where
|
||||
|
@ -57,7 +68,7 @@ pub(super) struct EagerRevWalk<T> {
|
|||
}
|
||||
|
||||
impl<T: Iterator> EagerRevWalk<T> {
|
||||
#[allow(unused)] // TODO
|
||||
#[cfg(test)] // TODO
|
||||
pub fn new(iter: T) -> Self {
|
||||
EagerRevWalk { iter: iter.fuse() }
|
||||
}
|
||||
|
@ -71,6 +82,48 @@ impl<I: ?Sized, T: Iterator> RevWalk<I> for EagerRevWalk<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[must_use]
|
||||
pub(super) struct PeekableRevWalk<I: ?Sized, W: RevWalk<I>> {
|
||||
walk: W,
|
||||
// Since RevWalk is fused, we don't need a nested Option<Option<_>>.
|
||||
peeked: Option<W::Item>,
|
||||
}
|
||||
|
||||
impl<I: ?Sized, W: RevWalk<I>> PeekableRevWalk<I, W> {
|
||||
#[cfg(test)] // TODO
|
||||
pub fn peek(&mut self, index: &I) -> Option<&W::Item> {
|
||||
if self.peeked.is_none() {
|
||||
self.peeked = self.walk.next(index);
|
||||
}
|
||||
self.peeked.as_ref()
|
||||
}
|
||||
|
||||
#[cfg(test)] // TODO
|
||||
pub fn next_if(
|
||||
&mut self,
|
||||
index: &I,
|
||||
predicate: impl FnOnce(&W::Item) -> bool,
|
||||
) -> Option<W::Item> {
|
||||
match self.next(index) {
|
||||
Some(item) if predicate(&item) => Some(item),
|
||||
other => {
|
||||
assert!(self.peeked.is_none());
|
||||
self.peeked = other;
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: ?Sized, W: RevWalk<I>> RevWalk<I> for PeekableRevWalk<I, W> {
|
||||
type Item = W::Item;
|
||||
|
||||
fn next(&mut self, index: &I) -> Option<Self::Item> {
|
||||
self.peeked.take().or_else(|| self.walk.next(index))
|
||||
}
|
||||
}
|
||||
|
||||
/// Adapter that turns `RevWalk` into `Iterator` by attaching borrowed `index`.
|
||||
#[derive(Clone, Debug)]
|
||||
#[must_use]
|
||||
|
@ -701,6 +754,30 @@ mod tests {
|
|||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_peekable_rev_walk() {
|
||||
let source = EagerRevWalk::new(vec![0, 1, 2, 3].into_iter());
|
||||
let mut peekable = source.peekable();
|
||||
assert_eq!(peekable.peek(&()), Some(&0));
|
||||
assert_eq!(peekable.peek(&()), Some(&0));
|
||||
assert_eq!(peekable.next(&()), Some(0));
|
||||
assert_eq!(peekable.peeked, None);
|
||||
assert_eq!(peekable.next_if(&(), |&v| v == 2), None);
|
||||
assert_eq!(peekable.next(&()), Some(1));
|
||||
assert_eq!(peekable.next_if(&(), |&v| v == 2), Some(2));
|
||||
assert_eq!(peekable.peeked, None);
|
||||
assert_eq!(peekable.peek(&()), Some(&3));
|
||||
assert_eq!(peekable.next_if(&(), |&v| v == 3), Some(3));
|
||||
assert_eq!(peekable.peeked, None);
|
||||
assert_eq!(peekable.next(&()), None);
|
||||
assert_eq!(peekable.next(&()), None);
|
||||
|
||||
let source = EagerRevWalk::new((vec![] as Vec<i32>).into_iter());
|
||||
let mut peekable = source.peekable();
|
||||
assert_eq!(peekable.peek(&()), None);
|
||||
assert_eq!(peekable.next(&()), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_walk_ancestors() {
|
||||
let mut new_change_id = change_id_generator();
|
||||
|
|
Loading…
Reference in a new issue