diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 16917443..88956dee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,6 +54,7 @@ jobs: cargo check --workspace cargo build --workspace cargo test --all-targets + cargo test --doc - name: Show SCCache stats if: always() && !cancelled() diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index b06fb00c..a3bdccaf 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -48,7 +48,7 @@ jobs: - name: Build docs run: | set -eufo pipefail - cargo doc --no-deps + cargo doc --document-private-items --no-deps rm target/doc/.lock echo '' > target/doc/index.html diff --git a/Cargo.toml b/Cargo.toml index a51df77d..091b263e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,10 +26,6 @@ suspicious = { level = "deny", priority = -1 } # Personal Preferences module_name_repetitions = "allow" -# FIXME: Strict -missing_panics_doc = "allow" -missing_errors_doc = "allow" - [profile.dev.package] insta.opt-level = 3 similar.opt-level = 3 diff --git a/src/path.rs b/src/path.rs index c47e2ba3..a4274261 100644 --- a/src/path.rs +++ b/src/path.rs @@ -1,39 +1,65 @@ use crate::{decode::percent_decode, errors::decode::DecodeError}; use std::borrow::Cow; +/// [`Path`] stores the URI data to be used to search for a matching route in a [`Router`](crate::Router). #[derive(Debug)] pub struct Path<'path> { + /// Original, unaltered path bytes. + raw: &'path [u8], + + /// Percent-decoded path bytes. decoded: Cow<'path, [u8]>, } impl<'path> Path<'path> { + /// Creates a new [`Path`] instance from a URI path string. + /// + /// # Errors + /// + /// Will error if the path fails percent-decoding. + /// + /// # Examples + /// + /// ## Valid + /// + /// ```rust + /// let path = wayfind::Path::new("/hello%20world").unwrap(); + /// assert_eq!(path.raw_bytes(), b"/hello%20world"); + /// assert_eq!(path.decoded_bytes(), b"/hello world"); + /// ``` + /// + /// ## Invalid + /// + /// ```rust + /// let path = wayfind::Path::new("/hello%GGworld").unwrap_err(); + /// let error = " + /// invalid percent-encoding + /// + /// Input: /hello%GGworld + /// ^^^ + /// + /// Expected: '%' followed by two hexadecimal digits (a-F, 0-9) + /// Found: '%GG' + /// "; + /// + /// assert_eq!(path.to_string(), error.trim()); + /// ``` pub fn new(path: &'path str) -> Result { Ok(Self { + raw: path.as_bytes(), decoded: percent_decode(path.as_bytes())?, }) } + /// Returns a reference to the original path bytes. #[must_use] - pub fn decoded_bytes(&'path self) -> &'path [u8] { - &self.decoded + pub const fn raw_bytes(&'path self) -> &'path [u8] { + self.raw } -} - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn test_path_invalid_encoding() { - let error = Path::new("/hello%20world%GG").unwrap_err(); - insta::assert_snapshot!(error, @r###" - invalid percent-encoding - - Input: /hello%20world%GG - ^^^ - - Expected: '%' followed by two hexadecimal digits (a-F, 0-9) - Found: '%GG' - "###); + /// Returns a reference to the percent-decoded path bytes. + #[must_use] + pub fn decoded_bytes(&'path self) -> &'path [u8] { + &self.decoded } } diff --git a/src/router.rs b/src/router.rs index ee0affab..eeba9d2c 100644 --- a/src/router.rs +++ b/src/router.rs @@ -28,6 +28,7 @@ pub struct Router { impl Router { #[must_use] + #[allow(clippy::missing_panics_doc)] pub fn new() -> Self { let mut router = Self { root: Node { @@ -68,6 +69,7 @@ impl Router { router } + #[allow(clippy::missing_errors_doc)] pub fn constraint(&mut self) -> Result<(), ConstraintError> { match self.constraints.entry(C::NAME.as_bytes().to_vec()) { Entry::Vacant(entry) => { @@ -86,6 +88,7 @@ impl Router { } } + #[allow(clippy::missing_errors_doc)] pub fn insert(&mut self, route: &str, value: T) -> Result<(), InsertError> { let path = Path::new(route)?; if route.as_bytes() != path.decoded_bytes() { @@ -119,6 +122,7 @@ impl Router { self.root.insert(&mut parts, NodeData { path, value }) } + #[allow(clippy::missing_errors_doc)] pub fn delete(&mut self, route: &str) -> Result<(), DeleteError> { let mut parts = Parts::new(route.as_bytes())?; self.root.delete(&mut parts) diff --git a/tests/common.rs b/tests/common.rs index e42dd788..bd6da651 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -44,6 +44,7 @@ pub struct ExpectedMatch<'k, 'v, T> { pub params: Vec>, } +#[allow(clippy::missing_panics_doc)] pub fn assert_router_match<'a, T: PartialEq + Debug>( router: &'a Router, input: &'a str,