mirror of
https://github.com/martinvonz/jj.git
synced 2025-02-01 00:50:57 +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
|
// The following methods are provided for convenience. They are not supposed
|
||||||
// to be reimplemented.
|
// 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`.
|
/// Reattaches the underlying `index`.
|
||||||
fn attach(self, index: &I) -> RevWalkBorrowedIndexIter<'_, I, Self>
|
fn attach(self, index: &I) -> RevWalkBorrowedIndexIter<'_, I, Self>
|
||||||
where
|
where
|
||||||
|
@ -57,7 +68,7 @@ pub(super) struct EagerRevWalk<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Iterator> EagerRevWalk<T> {
|
impl<T: Iterator> EagerRevWalk<T> {
|
||||||
#[allow(unused)] // TODO
|
#[cfg(test)] // TODO
|
||||||
pub fn new(iter: T) -> Self {
|
pub fn new(iter: T) -> Self {
|
||||||
EagerRevWalk { iter: iter.fuse() }
|
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`.
|
/// Adapter that turns `RevWalk` into `Iterator` by attaching borrowed `index`.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -701,6 +754,30 @@ mod tests {
|
||||||
.collect()
|
.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]
|
#[test]
|
||||||
fn test_walk_ancestors() {
|
fn test_walk_ancestors() {
|
||||||
let mut new_change_id = change_id_generator();
|
let mut new_change_id = change_id_generator();
|
||||||
|
|
Loading…
Reference in a new issue