# HG changeset patch
# User Georges Racinet <georges.racinet@octobus.net>
# Date 1693434811 -7200
#      Thu Aug 31 00:33:31 2023 +0200
# Branch stable
# Node ID b4465e96862f36d6ecb401c4421b4ccc8a274630
# Parent  831f85fc375aaee165c6e9ac6e1811bf9eda831a
rhgitaly::util::common_subpath_split

This utility method finds the greatest common denominator of
two paths, and helps using the remainder in one of them.

It takes care of the various edge cases (strict equality,
trailing slashes) and will be used several times in the
`GetTreeEntries` implementation.

diff --git a/rust/rhgitaly/src/util.rs b/rust/rhgitaly/src/util.rs
--- a/rust/rhgitaly/src/util.rs
+++ b/rust/rhgitaly/src/util.rs
@@ -21,3 +21,89 @@
         }
     }
 }
+
+/// Return the common subpath as a subslice of `first` and the index after which the remainder
+/// starts in `second`.
+pub fn common_subpath_split<'a, 'b>(first: &'a [u8], second: &'b [u8]) -> (&'a [u8], usize) {
+    // position of the latest slash in `first` after the common subpath, if any.
+    let mut latest_slash: Option<usize> = None;
+
+    let mut fit = first.iter();
+    let mut sit = second.iter();
+    let mut i: usize = 0;
+
+    loop {
+        match fit.next() {
+            Some(fc) => match sit.next() {
+                None => {
+                    if *fc == b'/' {
+                        latest_slash = Some(i);
+                    }
+                    else{ break;}
+                }
+                Some(sc) => {
+                    if *fc != *sc {
+                        break;
+                    }
+                    if *fc == b'/' {
+                        latest_slash = Some(i);
+                    }
+                    i += 1;
+                }
+            },
+            None => match sit.next() {
+                None => {
+                    return (first, first.len());
+                }
+                Some(sc) => {
+                    if *sc == b'/' {
+                        return (first, first.len() + 1);
+                    } else {
+                        break;
+                    }
+                }
+            },
+        }
+    }
+
+    match latest_slash {
+        None => (&[], 0),
+        Some(ls) => (&first[..ls], ls + 1),
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+
+    #[test]
+    fn test_common_subpath_split() {
+        assert_eq!(common_subpath_split(b"foo/a", b"bar"), (b"".as_ref(), 0));
+        assert_eq!(common_subpath_split(b"bar", b"foo/a"), (b"".as_ref(), 0));
+        assert_eq!(
+            common_subpath_split(b"foo/a", b"foo/b"),
+            (b"foo".as_ref(), 4)
+        );
+        assert_eq!(common_subpath_split(b"foo/a", b"foox/a"), (b"".as_ref(), 0));
+        assert_eq!(common_subpath_split(b"foox/a", b"foo/a"), (b"".as_ref(), 0));
+        assert_eq!(
+            common_subpath_split(b"foo/a/", b"foo/a/b"),
+            (b"foo/a".as_ref(), 6)
+        );
+        assert_eq!(
+            common_subpath_split(b"foo/a", b"foo/a/b"),
+            (b"foo/a".as_ref(), 6)
+        );
+        assert_eq!(
+            common_subpath_split(b"foo/a/b", b"foo/a"),
+            (b"foo/a".as_ref(), 6)
+        );
+        assert_eq!(
+            common_subpath_split(b"foo/a/b/c", b"foo/a/d/e"),
+            (b"foo/a".as_ref(), 6)
+        );
+        assert_eq!(common_subpath_split(b"", b"foo/a"), (b"".as_ref(), 0));
+        assert_eq!(common_subpath_split(b"foo/a", b""), (b"".as_ref(), 0));
+    }
+}