[PATCH 1 of 2] rust-dirstate: add helper to iterate ancestor paths

Martin von Zweigbergk martinvonz at google.com
Wed Jul 10 10:36:26 EDT 2019


On Sun, Jun 30, 2019, 04:17 Yuya Nishihara <yuya at tcha.org> wrote:

> # HG changeset patch
> # User Yuya Nishihara <yuya at tcha.org>
> # Date 1561887163 -32400
> #      Sun Jun 30 18:32:43 2019 +0900
> # Node ID 72ab74c704053b2212b874a902574fedadad4252
> # Parent  904e0da2e195d2a29977ceccdd25480233c34d7a
> rust-dirstate: add helper to iterate ancestor paths
>
> This is modeled after std::path::Path::ancestors().
>
> find_dirs(b"") yields b"" because Mercurial's util.finddirs() works in that
> way, and the test case for DirsMultiset expects such behavior.
>

That's also how std::path::Path::ancestors() works, it seems.


> diff --git a/rust/hg-core/src/utils/files.rs b/rust/hg-core/src/utils/
> files.rs
> --- a/rust/hg-core/src/utils/files.rs
> +++ b/rust/hg-core/src/utils/files.rs
> @@ -1,3 +1,4 @@
> +use std::iter::FusedIterator;
>  use std::path::Path;
>
>  pub fn get_path_from_bytes(bytes: &[u8]) -> &Path {
> @@ -17,3 +18,66 @@ pub fn get_path_from_bytes(bytes: &[u8])
>
>      Path::new(os_str)
>  }
> +
> +/// An iterator over repository path yielding itself and its ancestors.
> +#[derive(Copy, Clone, Debug)]
> +pub struct Ancestors<'a> {
> +    next: Option<&'a [u8]>,
> +}
> +
> +impl<'a> Iterator for Ancestors<'a> {
> +    // if we had an HgPath type, this would yield &'a HgPath
> +    type Item = &'a [u8];
> +
> +    fn next(&mut self) -> Option<Self::Item> {
> +        let next = self.next;
> +        self.next = match self.next {
> +            Some(s) if s.is_empty() => None,
> +            Some(s) => {
> +                let p = s.iter().rposition(|&c| c == b'/').unwrap_or(0);
> +                Some(&s[..p])
> +            }
> +            None => None,
> +        };
> +        next
> +    }
> +}
> +
> +impl<'a> FusedIterator for Ancestors<'a> {}
> +
> +/// Returns an iterator yielding ancestor directories of the given
> repository
> +/// path.
> +///
> +/// The path is separated by '/', and must not start with '/'.
> +///
> +/// The path itself isn't included unless it is b"" (meaning the root
> +/// directory.)
> +pub fn find_dirs<'a>(path: &'a [u8]) -> Ancestors<'a> {
> +    let mut dirs = Ancestors { next: Some(path) };
> +    if !path.is_empty() {
> +        dirs.next(); // skip itself
> +    }
> +    dirs
> +}
> +
> +#[cfg(test)]
> +mod tests {
> +    #[test]
> +    fn find_dirs_some() {
> +        let mut dirs = super::find_dirs(b"foo/bar/baz");
> +        assert_eq!(dirs.next(), Some(b"foo/bar".as_ref()));
> +        assert_eq!(dirs.next(), Some(b"foo".as_ref()));
> +        assert_eq!(dirs.next(), Some(b"".as_ref()));
> +        assert_eq!(dirs.next(), None);
> +        assert_eq!(dirs.next(), None);
> +    }
> +
> +    #[test]
> +    fn find_dirs_empty() {
> +        // looks weird, but mercurial.util.finddirs(b"") yields b""
> +        let mut dirs = super::find_dirs(b"");
> +        assert_eq!(dirs.next(), Some(b"".as_ref()));
> +        assert_eq!(dirs.next(), None);
> +        assert_eq!(dirs.next(), None);
> +    }
> +}
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.mercurial-scm.org/pipermail/mercurial-devel/attachments/20190710/5e182218/attachment.html>


More information about the Mercurial-devel mailing list