Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(breaking): allow make PossibleRouteMatch dyn-safe #3421

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion router/src/matching/horizontal/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::{PartialPathMatch, PathSegment};
use std::sync::Arc;
mod param_segments;
mod static_segment;
mod tuples;
Expand All @@ -11,9 +12,37 @@ pub use static_segment::*;
/// This is a "horizontal" matching: i.e., it treats a tuple of route segments
/// as subsequent segments of the URL and tries to match them all.
pub trait PossibleRouteMatch {
const OPTIONAL: bool = false;
fn optional(&self) -> bool;

fn test<'a>(&self, path: &'a str) -> Option<PartialPathMatch<'a>>;

fn generate_path(&self, path: &mut Vec<PathSegment>);
}

impl PossibleRouteMatch for Box<dyn PossibleRouteMatch + Send + Sync> {
fn optional(&self) -> bool {
(**self).optional()
}

fn test<'a>(&self, path: &'a str) -> Option<PartialPathMatch<'a>> {
(**self).test(path)
}

fn generate_path(&self, path: &mut Vec<PathSegment>) {
(**self).generate_path(path);
}
}

impl PossibleRouteMatch for Arc<dyn PossibleRouteMatch + Send + Sync> {
fn optional(&self) -> bool {
(**self).optional()
}

fn test<'a>(&self, path: &'a str) -> Option<PartialPathMatch<'a>> {
(**self).test(path)
}

fn generate_path(&self, path: &mut Vec<PathSegment>) {
(**self).generate_path(path);
}
}
12 changes: 11 additions & 1 deletion router/src/matching/horizontal/param_segments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ use std::borrow::Cow;
pub struct ParamSegment(pub &'static str);

impl PossibleRouteMatch for ParamSegment {
fn optional(&self) -> bool {
false
}

fn test<'a>(&self, path: &'a str) -> Option<PartialPathMatch<'a>> {
let mut matched_len = 0;
let mut param_offset = 0;
Expand Down Expand Up @@ -121,6 +125,10 @@ impl PossibleRouteMatch for ParamSegment {
pub struct WildcardSegment(pub &'static str);

impl PossibleRouteMatch for WildcardSegment {
fn optional(&self) -> bool {
false
}

fn test<'a>(&self, path: &'a str) -> Option<PartialPathMatch<'a>> {
let mut matched_len = 0;
let mut param_offset = 0;
Expand Down Expand Up @@ -158,7 +166,9 @@ impl PossibleRouteMatch for WildcardSegment {
pub struct OptionalParamSegment(pub &'static str);

impl PossibleRouteMatch for OptionalParamSegment {
const OPTIONAL: bool = true;
fn optional(&self) -> bool {
true
}

fn test<'a>(&self, path: &'a str) -> Option<PartialPathMatch<'a>> {
let mut matched_len = 0;
Expand Down
8 changes: 8 additions & 0 deletions router/src/matching/horizontal/static_segment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ use super::{PartialPathMatch, PathSegment, PossibleRouteMatch};
use std::fmt::Debug;

impl PossibleRouteMatch for () {
fn optional(&self) -> bool {
false
}

fn test<'a>(&self, path: &'a str) -> Option<PartialPathMatch<'a>> {
Some(PartialPathMatch::new(path, vec![], ""))
}
Expand Down Expand Up @@ -54,6 +58,10 @@ impl AsPath for &'static str {
pub struct StaticSegment<T: AsPath>(pub T);

impl<T: AsPath> PossibleRouteMatch for StaticSegment<T> {
fn optional(&self) -> bool {
false
}

fn test<'a>(&self, path: &'a str) -> Option<PartialPathMatch<'a>> {
let mut matched_len = 0;
let mut test = path.chars().peekable();
Expand Down
26 changes: 18 additions & 8 deletions router/src/matching/horizontal/tuples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,21 @@ macro_rules! tuples {
$first: PossibleRouteMatch,
$($ty: PossibleRouteMatch),*,
{
fn optional(&self) -> bool {
#[allow(non_snake_case)]
let ($first, $($ty,)*) = &self;
[$first.optional(), $($ty.optional()),*].into_iter().any(|n| n)
}

fn test<'a>(&self, path: &'a str) -> Option<PartialPathMatch<'a>> {
#[allow(non_snake_case)]
let ($first, $($ty,)*) = &self;

// on the first run, include all optionals
let mut include_optionals = {
[$first::OPTIONAL, $($ty::OPTIONAL),*].into_iter().filter(|n| *n).count()
[$first.optional(), $($ty.optional()),*].into_iter().filter(|n| *n).count()
};

#[allow(non_snake_case)]
let ($first, $($ty,)*) = &self;

loop {
let mut nth_field = 0;
let mut matched_len = 0;
Expand All @@ -25,7 +31,7 @@ macro_rules! tuples {
let mut p = Vec::new();
let mut m = String::new();

if !$first::OPTIONAL || nth_field < include_optionals {
if !$first.optional() || nth_field < include_optionals {
match $first.test(r) {
None => {
return None;
Expand All @@ -40,16 +46,16 @@ macro_rules! tuples {

matched_len += m.len();
$(
if $ty::OPTIONAL {
if $ty.optional() {
nth_field += 1;
}
if !$ty::OPTIONAL || nth_field < include_optionals {
if !$ty.optional() || nth_field < include_optionals {
let PartialPathMatch {
remaining,
matched,
params
} = match $ty.test(r) {
None => if $ty::OPTIONAL {
None => if $ty.optional() {
return None;
} else {
if include_optionals == 0 {
Expand Down Expand Up @@ -90,6 +96,10 @@ where
Self: core::fmt::Debug,
A: PossibleRouteMatch,
{
fn optional(&self) -> bool {
self.0.optional()
}

fn test<'a>(&self, path: &'a str) -> Option<PartialPathMatch<'a>> {
let remaining = path;
let PartialPathMatch {
Expand Down
2 changes: 1 addition & 1 deletion router/src/matching/nested/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ impl<Segments, Children, Data, View> MatchNestedRoutes
for NestedRoute<Segments, Children, Data, View>
where
Self: 'static,
Segments: PossibleRouteMatch + std::fmt::Debug,
Segments: PossibleRouteMatch,
Children: MatchNestedRoutes,
Children::Match: MatchParams,
Children: 'static,
Expand Down
Loading