forked from mirrors/jj
tree: for walking tree, replace function with callback by iterator
Iterators are a lot easier to use.
This commit is contained in:
parent
4734eb6493
commit
8ec100713d
3 changed files with 68 additions and 31 deletions
|
@ -17,11 +17,14 @@ use std::fmt::{Debug, Error, Formatter};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::matchers::AlwaysMatcher;
|
use crate::matchers::AlwaysMatcher;
|
||||||
use crate::repo_path::{DirRepoPath, DirRepoPathComponent, FileRepoPath, RepoPath, RepoPathJoin};
|
use crate::repo_path::{
|
||||||
|
DirRepoPath, DirRepoPathComponent, FileRepoPath, RepoPath, RepoPathComponent, RepoPathJoin,
|
||||||
|
};
|
||||||
use crate::store;
|
use crate::store;
|
||||||
use crate::store::{ConflictId, TreeEntriesIter, TreeEntry, TreeId, TreeValue};
|
use crate::store::{ConflictId, TreeEntriesIter, TreeEntry, TreeId, TreeValue};
|
||||||
use crate::store_wrapper::StoreWrapper;
|
use crate::store_wrapper::StoreWrapper;
|
||||||
use crate::trees::{recursive_tree_diff, walk_entries, TreeValueDiff};
|
use crate::trees::{recursive_tree_diff, TreeValueDiff};
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Tree {
|
pub struct Tree {
|
||||||
|
@ -91,6 +94,10 @@ impl Tree {
|
||||||
self.data.entries()
|
self.data.entries()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn entries_recursive(&self) -> TreeWalk {
|
||||||
|
TreeWalk::new(self.clone())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn entry<N>(&self, basename: &N) -> Option<TreeEntry>
|
pub fn entry<N>(&self, basename: &N) -> Option<TreeEntry>
|
||||||
where
|
where
|
||||||
N: Borrow<str> + ?Sized,
|
N: Borrow<str> + ?Sized,
|
||||||
|
@ -187,13 +194,63 @@ impl Tree {
|
||||||
|
|
||||||
pub fn conflicts(&self) -> Vec<(RepoPath, ConflictId)> {
|
pub fn conflicts(&self) -> Vec<(RepoPath, ConflictId)> {
|
||||||
let mut conflicts = vec![];
|
let mut conflicts = vec![];
|
||||||
walk_entries(&self, &mut |name, value| -> Result<(), ()> {
|
for (name, value) in self.entries_recursive() {
|
||||||
if let TreeValue::Conflict(id) = value {
|
if let TreeValue::Conflict(id) = value {
|
||||||
conflicts.push((name.clone(), id.clone()));
|
conflicts.push((name.clone(), id.clone()));
|
||||||
}
|
}
|
||||||
Ok(())
|
}
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
conflicts
|
conflicts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TreeWalk {
|
||||||
|
stack: Vec<(Pin<Box<Tree>>, TreeEntriesIter<'static>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TreeWalk {
|
||||||
|
fn new(tree: Tree) -> Self {
|
||||||
|
let tree = Box::pin(tree);
|
||||||
|
let iter = tree.entries();
|
||||||
|
let iter: TreeEntriesIter<'static> = unsafe { std::mem::transmute(iter) };
|
||||||
|
Self {
|
||||||
|
stack: vec![(tree, iter)],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for TreeWalk {
|
||||||
|
type Item = (RepoPath, TreeValue);
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
while !self.stack.is_empty() {
|
||||||
|
let (tree, iter) = self.stack.last_mut().unwrap();
|
||||||
|
match iter.next() {
|
||||||
|
None => {
|
||||||
|
// No more entries in this directory
|
||||||
|
self.stack.pop().unwrap();
|
||||||
|
}
|
||||||
|
Some(entry) => {
|
||||||
|
match entry.value() {
|
||||||
|
TreeValue::Tree(id) => {
|
||||||
|
let subtree =
|
||||||
|
tree.known_sub_tree(&DirRepoPathComponent::from(entry.name()), id);
|
||||||
|
let subtree = Box::pin(subtree);
|
||||||
|
let iter = subtree.entries();
|
||||||
|
let subtree_iter: TreeEntriesIter<'static> =
|
||||||
|
unsafe { std::mem::transmute(iter) };
|
||||||
|
self.stack.push((subtree, subtree_iter));
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
let path = RepoPath::new(
|
||||||
|
tree.dir().clone(),
|
||||||
|
RepoPathComponent::from(entry.name()),
|
||||||
|
);
|
||||||
|
return Some((path, other.clone()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -16,33 +16,13 @@ use crate::files;
|
||||||
use crate::files::MergeResult;
|
use crate::files::MergeResult;
|
||||||
use crate::matchers::Matcher;
|
use crate::matchers::Matcher;
|
||||||
use crate::repo_path::{
|
use crate::repo_path::{
|
||||||
DirRepoPath, DirRepoPathComponent, FileRepoPath, FileRepoPathComponent, RepoPath,
|
DirRepoPath, DirRepoPathComponent, FileRepoPath, FileRepoPathComponent, RepoPathJoin,
|
||||||
RepoPathComponent, RepoPathJoin,
|
|
||||||
};
|
};
|
||||||
use crate::store::{Conflict, ConflictPart, StoreError, TreeId, TreeValue};
|
use crate::store::{Conflict, ConflictPart, StoreError, TreeId, TreeValue};
|
||||||
use crate::store_wrapper::StoreWrapper;
|
use crate::store_wrapper::StoreWrapper;
|
||||||
use crate::tree::Tree;
|
use crate::tree::Tree;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
pub fn walk_entries<E>(
|
|
||||||
tree: &Tree,
|
|
||||||
callback: &mut impl FnMut(&RepoPath, &TreeValue) -> Result<(), E>,
|
|
||||||
) -> Result<(), E> {
|
|
||||||
for entry in tree.entries() {
|
|
||||||
let path = RepoPath::new(tree.dir().clone(), RepoPathComponent::from(entry.name()));
|
|
||||||
match entry.value() {
|
|
||||||
TreeValue::Tree(id) => {
|
|
||||||
let subtree = tree.known_sub_tree(&DirRepoPathComponent::from(entry.name()), id);
|
|
||||||
walk_entries(&subtree, callback)?;
|
|
||||||
}
|
|
||||||
other => {
|
|
||||||
callback(&path, other)?;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum Diff<T> {
|
pub enum Diff<T> {
|
||||||
Modified(T, T),
|
Modified(T, T),
|
||||||
|
|
|
@ -47,7 +47,7 @@ use jj_lib::settings::UserSettings;
|
||||||
use jj_lib::store::{CommitId, Timestamp};
|
use jj_lib::store::{CommitId, Timestamp};
|
||||||
use jj_lib::store::{StoreError, TreeValue};
|
use jj_lib::store::{StoreError, TreeValue};
|
||||||
use jj_lib::tree::Tree;
|
use jj_lib::tree::Tree;
|
||||||
use jj_lib::trees::{walk_entries, TreeValueDiff};
|
use jj_lib::trees::TreeValueDiff;
|
||||||
use jj_lib::working_copy::{CheckoutStats, WorkingCopy};
|
use jj_lib::working_copy::{CheckoutStats, WorkingCopy};
|
||||||
|
|
||||||
use self::chrono::{FixedOffset, TimeZone, Utc};
|
use self::chrono::{FixedOffset, TimeZone, Utc};
|
||||||
|
@ -565,10 +565,10 @@ fn cmd_files(
|
||||||
let mut repo = get_repo(ui, &matches)?;
|
let mut repo = get_repo(ui, &matches)?;
|
||||||
let mut_repo = Arc::get_mut(&mut repo).unwrap();
|
let mut_repo = Arc::get_mut(&mut repo).unwrap();
|
||||||
let commit = resolve_revision_arg(ui, mut_repo, sub_matches)?;
|
let commit = resolve_revision_arg(ui, mut_repo, sub_matches)?;
|
||||||
walk_entries(&commit.tree(), &mut |name, _value| {
|
for (name, _value) in commit.tree().entries_recursive() {
|
||||||
writeln!(ui, "{}", name.to_internal_string());
|
writeln!(ui, "{}", name.to_internal_string());
|
||||||
Ok(())
|
}
|
||||||
})
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_diff(left: &[u8], right: &[u8], styler: &mut dyn Styler) {
|
fn print_diff(left: &[u8], right: &[u8], styler: &mut dyn Styler) {
|
||||||
|
|
Loading…
Reference in a new issue