Skip to content

Commit

Permalink
Merge pull request #126 from DuskSystems/125-begin-documenting-crate
Browse files Browse the repository at this point in the history
Document finished features
  • Loading branch information
CathalMullan authored Aug 27, 2024
2 parents 3a35573 + c08ccf3 commit 0b2d6b4
Show file tree
Hide file tree
Showing 35 changed files with 603 additions and 98 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
4 changes: 0 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions benches/matchit_criterion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ fn benchmark(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("matchit benchmarks");

group.bench_function("matchit benchmarks/wayfind", |bencher| {
let mut router = wayfind::router::Router::new();
let mut router = wayfind::Router::new();
for route in routes!(brackets) {
router.insert(route, true).unwrap();
}

bencher.iter(|| {
for route in black_box(paths()) {
let path = wayfind::path::Path::new(route).unwrap();
let path = wayfind::Path::new(route).unwrap();
let output = black_box(router.search(black_box(&path)).unwrap());
let _parameters: Vec<(&str, &str)> =
black_box(output.parameters.iter().map(|p| (p.key, p.value)).collect());
Expand Down
4 changes: 2 additions & 2 deletions benches/matchit_divan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ fn main() {

#[divan::bench(name = "wayfind")]
fn wayfind(bencher: divan::Bencher) {
let mut router = wayfind::router::Router::new();
let mut router = wayfind::Router::new();
for route in routes!(brackets) {
router.insert(route, true).unwrap();
}

bencher.bench(|| {
for route in black_box(paths()) {
let path = wayfind::path::Path::new(route).unwrap();
let path = wayfind::Path::new(route).unwrap();
let output = black_box(router.search(black_box(&path)).unwrap());
let _parameters: Vec<(&str, &str)> =
black_box(output.parameters.iter().map(|p| (p.key, p.value)).collect());
Expand Down
4 changes: 2 additions & 2 deletions benches/path_tree_criterion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ fn benchmark(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group("path-tree benchmarks");

group.bench_function("path-tree benchmarks/wayfind", |bencher| {
let mut router = wayfind::router::Router::new();
let mut router = wayfind::Router::new();
for (index, route) in routes!(brackets).iter().enumerate() {
router.insert(route, index).unwrap();
}

bencher.iter(|| {
for route in black_box(paths()) {
let path = wayfind::path::Path::new(route).unwrap();
let path = wayfind::Path::new(route).unwrap();
let output = black_box(router.search(black_box(&path)).unwrap());
let _parameters: Vec<(&str, &str)> =
black_box(output.parameters.iter().map(|p| (p.key, p.value)).collect());
Expand Down
4 changes: 2 additions & 2 deletions benches/path_tree_divan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ fn main() {

#[divan::bench(name = "wayfind")]
fn wayfind(bencher: divan::Bencher) {
let mut router = wayfind::router::Router::new();
let mut router = wayfind::Router::new();
for (index, route) in routes!(brackets).iter().enumerate() {
router.insert(route, index).unwrap();
}

bencher.bench(|| {
for route in black_box(paths()) {
let path = wayfind::path::Path::new(route).unwrap();
let path = wayfind::Path::new(route).unwrap();
let output = black_box(router.search(black_box(&path)).unwrap());
let _parameters: Vec<(&str, &str)> =
black_box(output.parameters.iter().map(|p| (p.key, p.value)).collect());
Expand Down
2 changes: 1 addition & 1 deletion examples/axum-fork/src/routing/path_router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use axum_core::response::IntoResponse;
use std::{borrow::Cow, collections::HashMap, convert::Infallible, fmt, sync::Arc};
use tower_layer::Layer;
use tower_service::Service;
use wayfind::{errors::insert::InsertError, node::search::Match, path::Path, router::Router};
use wayfind::{errors::InsertError, Match, Path, Router};

use super::{
future::RouteFuture, not_found::NotFound, strip_prefix::StripPrefix, url_params, Endpoint,
Expand Down
2 changes: 1 addition & 1 deletion examples/axum-fork/src/routing/url_params.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::util::PercentDecodedStr;
use http::Extensions;
use std::sync::Arc;
use wayfind::node::search::Parameter;
use wayfind::Parameter;

#[derive(Clone)]
pub(crate) enum UrlParams {
Expand Down
2 changes: 1 addition & 1 deletion examples/hyper/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::{
sync::Arc,
};
use tokio::{net::TcpListener, task::JoinSet};
use wayfind::{node::search::Parameter, path::Path, router::Router};
use wayfind::{Parameter, Path, Router};

type BoxFuture<'a> = Pin<
Box<
Expand Down
1 change: 1 addition & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
})
sccache
cargo-insta
cargo-watch

# Benchmarking
cargo-codspeed
Expand Down
2 changes: 1 addition & 1 deletion fuzz/fuzz_targets/insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use libfuzzer_sys::fuzz_target;

fuzz_target!(|data: &[u8]| {
let mut router = wayfind::router::Router::new();
let mut router = wayfind::Router::new();
if let Ok(route) = std::str::from_utf8(data) {
let _ = router.insert(route, true);
}
Expand Down
28 changes: 27 additions & 1 deletion src/constraints.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,34 @@
use std::net::{Ipv4Addr, Ipv6Addr};

pub trait Constraint {
/// A constraint that can be used for custom path routing logic.
///
/// Must be a stateless, static check.
/// In the future, we may support stateful constraints.
///
/// Constraints can be registered within a [`Router`](crate::Router) via the [`constraint`](crate::Router::constraint) function.
///
/// # Example
///
/// ```rust
/// use wayfind::Constraint;
///
/// struct HelloConstraint;
/// impl Constraint for HelloConstraint {
/// const NAME: &'static str = "hello";
///
/// fn check(segment: &str) -> bool {
/// segment == "hello"
/// }
/// }
/// ```
pub trait Constraint: Send + Sync {
/// The name of the constraint.
///
/// Must be unique within a given router.
/// Try and avoid generic constraint names like `id`.
const NAME: &'static str;

/// Checks if a given segment matches this constraint.
fn check(segment: &str) -> bool;
}

Expand Down
4 changes: 3 additions & 1 deletion src/decode.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::errors::decode::DecodeError;
use std::borrow::Cow;

pub(crate) fn percent_decode(input: &[u8]) -> Result<Cow<[u8]>, DecodeError> {
/// Try and percent-decode input bytes.
/// Does not do any sort of normalization, simply decodes hex characters.
pub fn percent_decode(input: &[u8]) -> Result<Cow<[u8]>, DecodeError> {
if !input.contains(&b'%') {
return Ok(Cow::Borrowed(input));
}
Expand Down
23 changes: 18 additions & 5 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
pub mod constraint;
pub mod decode;
pub mod delete;
pub mod insert;
pub mod route;
//! Error types for [`wayfind`](crate).
//!
//! All errors contain a user-friendly display method.
pub(crate) mod constraint;
pub use constraint::ConstraintError;

pub(crate) mod decode;
pub use decode::DecodeError;

pub(crate) mod delete;
pub use delete::DeleteError;

pub(crate) mod insert;
pub use insert::InsertError;

pub(crate) mod route;
pub use route::RouteError;
33 changes: 33 additions & 0 deletions src/errors/constraint.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,43 @@
use std::{error::Error, fmt::Display};

/// Errors relating to constraints.
#[derive(Debug, PartialEq, Eq)]
pub enum ConstraintError {
/// Constraint name is already in use.
///
/// # Examples
///
/// ```rust
/// use wayfind::errors::ConstraintError;
///
/// let error = ConstraintError::DuplicateName {
/// name: "my_constraint",
/// existing_type: "my_crate::constraints::A",
/// new_type: "my_crate::constraints::B",
/// };
///
/// let display = "
/// duplicate constraint name
///
/// The constraint name 'my_constraint' is already in use:
/// - existing constraint type: 'my_crate::constraints::A'
/// - new constraint type: 'my_crate::constraints::B'
///
/// help: each constraint must have a unique name
///
/// try:
/// - Check if you have accidentally added the same constraint twice
/// - Ensure different constraints have different names
/// ";
///
/// assert_eq!(error.to_string(), display.trim());
/// ```
DuplicateName {
/// The name of the constraint.
name: &'static str,
/// The [`type_name`](std::any::type_name) of the already existing constraint.
existing_type: &'static str,
/// The [`type_name`](std::any::type_name) of the attempted new constraint.
new_type: &'static str,
},
}
Expand Down
29 changes: 29 additions & 0 deletions src/errors/decode.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,39 @@
use std::{error::Error, fmt::Display};

/// Errors relating to percent-decoding failures.
#[derive(Debug, PartialEq, Eq)]
pub enum DecodeError {
/// Invalid percent-encoding sequence encountered.
///
/// # Examples
///
/// ```rust
/// use wayfind::errors::DecodeError;
///
/// let error = DecodeError::InvalidEncoding {
/// input: "/hello%GGworld".to_string(),
/// position: 6,
/// character: [b'%', b'G', b'G'],
/// };
///
/// let display = "
/// invalid percent-encoding
///
/// Input: /hello%GGworld
/// ^^^
///
/// Expected: '%' followed by two hexadecimal digits (a-F, 0-9)
/// Found: '%GG'
/// ";
///
/// assert_eq!(error.to_string(), display.trim());
/// ```
InvalidEncoding {
/// The unaltered input string.
input: String,
/// The position in the input where the invalid encoding was found.
position: usize,
/// The invalid character sequence.
character: [u8; 3],
},
}
Expand Down
29 changes: 28 additions & 1 deletion src/errors/delete.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,37 @@
use super::route::RouteError;
use std::{error::Error, fmt::Display};

/// Errors relating to attempting to delete a route from a [`Router`](crate::Router).
#[derive(Debug, PartialEq, Eq)]
pub enum DeleteError {
/// A [`RouteError`] that occurred during the delete.
RouteError(RouteError),
NotFound { path: String },

/// Path to be deleted was not found in the router.
///
/// # Examples
///
/// ```rust
/// use wayfind::errors::DeleteError;
///
/// let error = DeleteError::NotFound {
/// path: "/not_found".to_string(),
/// };
///
/// let display = "
/// not found
///
/// Path: /not_found
///
/// The specified path does not exist in the router
/// ";
///
/// assert_eq!(error.to_string(), display.trim());
/// ```
NotFound {
/// The path that was not found in the router.
path: String,
},
}

impl Error for DeleteError {}
Expand Down
Loading

0 comments on commit 0b2d6b4

Please sign in to comment.