//! A set of tree utilities used internally in the tree.rs module use crate::HashId; use git2::{Repository, Tree}; use std::{iter::Peekable, path::PathBuf, sync::Arc}; pub(super) trait PairIter where I: Iterator, { /// Step through fn pairs<'i, F: FnMut(K, Option<&K>)>(&'i mut self, cb: F); fn next_pair<'i>(&'i mut self) -> (Option, Option<&K>); } impl PairIter for Peekable where I: Iterator, { fn pairs<'i, F: FnMut(K, Option<&K>)>(&'i mut self, mut cb: F) { // Iterate until a->None while let (Some(a), b) = self.next_pair() { cb(a, b); } } fn next_pair<'i>(&'i mut self) -> (Option, Option<&K>) { (self.next(), self.peek()) } } /// Take a vector of path segments, and turn it into a valid offset path /// /// There are tests to make sure this function works properly. /// Following are some example transformations. /// /// * vec![] -> "" /// * vec!["foo"] -> "foo" /// * vec!["foo", "bar", "baz"] -> "foo/bar/baz" pub(super) fn path_segs_join(segments: Vec<&str>) -> String { segments .into_iter() .fold(PathBuf::new(), |buf, seg| buf.join(seg)) .as_path() .to_str() .unwrap() .to_owned() } /// Take an offset path inside the repository and split it into a vec pub(super) fn path_split(path: &str) -> Vec<&str> { path.split("/").filter(|s| s != &"").collect() } /// Compare a path and entry to a target buffer pub(super) fn path_cmp(target: &Vec<&str>, path: &str, entry: &str) -> bool { let mut buf = path_split(path); buf.push(entry); target == &buf } /// Open a tree for a particular commit pub(super) fn open_tree<'r>(repo: &'r Arc, c: &HashId) -> Option> { repo.find_commit(c.to_oid()).unwrap().tree().ok() } #[test] fn empty_path() { assert_eq!(path_segs_join(vec![]), String::from("")); } #[test] fn one_path() { assert_eq!(path_segs_join(vec!["foo".into()]), String::from("foo")); } #[test] fn nested_path() { assert_eq!( path_segs_join(vec!["foo".into(), "bar".into(), "baz".into()]), String::from("foo/bar/baz") ); } #[test] fn pair_iterator() { // The pair iterator needs access to `peek()` let mut i = vec![1, 2, 3, 4].into_iter().peekable(); assert_eq!(i.next_pair(), (Some(1), Some(&2))); assert_eq!(i.next_pair(), (Some(2), Some(&3))); assert_eq!(i.next_pair(), (Some(3), Some(&4))); assert_eq!(i.next_pair(), (Some(4), None)); }