瀏覽代碼

Modified Path parsing to add empty component for trailing slash.

Matthew Carr 3 年之前
父節點
當前提交
1aac0b0b7a
共有 1 個文件被更改,包括 30 次插入9 次删除
  1. 30 9
      crates/node/src/main.rs

+ 30 - 9
crates/node/src/main.rs

@@ -155,7 +155,9 @@ impl Display for PathError {
 }
 
 impl Path {
-    fn consume_component<I: Iterator<Item = (usize, char)>>(
+    /// Returns a result which, when successful, returns the index after the last character in the
+    /// current path component.
+    fn component_end<I: Iterator<Item = (usize, char)>>(
         start: usize, first: char, pairs: &mut I
     ) -> Result<usize, PathError> {
         if first == Path::SEP {
@@ -198,29 +200,39 @@ impl Path {
         };
         Ok(string)
     }
+
+    /// Asserts that the number of bytes in the given string is no more than `Path::BYTE_LIMIT`.
+    fn assert_not_too_long(string: &str) -> Result<(), PathError> {
+            let len = string.len();
+            if len > Path::BYTE_LIMIT {
+                return Err(PathError::PathTooLong(len))
+            }
+            Ok(())
+    }
 }
 
 impl<'s> TryFrom<&'s str> for Path {
     type Error = PathError;
 
     fn try_from(mut string: &'s str) -> Result<Path, PathError> {
-        {
-            let len = string.len();
-            if len >= Path::BYTE_LIMIT {
-                return Err(PathError::PathTooLong(len))
-            }
-        }
+        Path::assert_not_too_long(string)?;
         string = Path::trim_leading_sep(string)?;
         let mut pairs = string.char_indices();
         let mut components = Vec::new();
+        let mut last_end = 0;
         loop {
             let (start, end) = match pairs.next() {
-                Some((start, c)) => (start, Path::consume_component(start, c, &mut pairs)),
+                Some((start, c)) => (start, Path::component_end(start, c, &mut pairs)?),
                 None => break
             };
-            let slice = &string[start..end?];
+            last_end = end;
+            let slice = &string[start..end];
             components.push(slice.to_string());
         }
+        // An empty component is added to the end to indicate if there was a trailing slash.
+        if string.len() - 1 == last_end {
+            components.push("".to_string());
+        }
         Ok(Path(components))
     }
 }
@@ -296,6 +308,15 @@ mod tests {
         Ok(())
     }
 
+    #[test]
+    fn path_from_str_trailing_slash_ok() -> Result<(), PathError> {
+        let expected = Path(vec![
+            "orange".to_string(), "banana".to_string(), "shotgun".to_string(), "".to_string()
+        ]);
+        path_from_str_test_case(Ok(expected), "/orange/banana/shotgun/")?;
+        Ok(())
+    }
+
     #[test]
     fn path_from_str_path_too_long_fail() -> Result<(), PathError> {
         let expected = Err(PathError::PathTooLong(4097));