mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
feat: allow using enums for StaticSegment
by implementing AsPath
(#2685)
This commit is contained in:
parent
a2385e4c42
commit
873aec5787
1 changed files with 105 additions and 9 deletions
|
@ -1,6 +1,6 @@
|
||||||
use super::{PartialPathMatch, PathSegment, PossibleRouteMatch};
|
use super::{PartialPathMatch, PathSegment, PossibleRouteMatch};
|
||||||
use core::iter;
|
use core::iter;
|
||||||
use std::borrow::Cow;
|
use std::{borrow::Cow, fmt::Debug};
|
||||||
|
|
||||||
impl PossibleRouteMatch for () {
|
impl PossibleRouteMatch for () {
|
||||||
type ParamsIter = iter::Empty<(Cow<'static, str>, String)>;
|
type ParamsIter = iter::Empty<(Cow<'static, str>, String)>;
|
||||||
|
@ -15,10 +15,20 @@ impl PossibleRouteMatch for () {
|
||||||
fn generate_path(&self, _path: &mut Vec<PathSegment>) {}
|
fn generate_path(&self, _path: &mut Vec<PathSegment>) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
pub trait AsPath {
|
||||||
pub struct StaticSegment(pub &'static str);
|
fn as_path(&self) -> &'static str;
|
||||||
|
}
|
||||||
|
|
||||||
impl PossibleRouteMatch for StaticSegment {
|
impl AsPath for &'static str {
|
||||||
|
fn as_path(&self) -> &'static str {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct StaticSegment<T: AsPath>(pub T);
|
||||||
|
|
||||||
|
impl<T: AsPath> PossibleRouteMatch for StaticSegment<T> {
|
||||||
type ParamsIter = iter::Empty<(Cow<'static, str>, String)>;
|
type ParamsIter = iter::Empty<(Cow<'static, str>, String)>;
|
||||||
|
|
||||||
fn test<'a>(
|
fn test<'a>(
|
||||||
|
@ -27,17 +37,19 @@ impl PossibleRouteMatch for StaticSegment {
|
||||||
) -> Option<PartialPathMatch<'a, Self::ParamsIter>> {
|
) -> Option<PartialPathMatch<'a, Self::ParamsIter>> {
|
||||||
let mut matched_len = 0;
|
let mut matched_len = 0;
|
||||||
let mut test = path.chars().peekable();
|
let mut test = path.chars().peekable();
|
||||||
let mut this = self.0.chars();
|
let mut this = self.0.as_path().chars();
|
||||||
let mut has_matched = self.0.is_empty() || self.0 == "/";
|
let mut has_matched =
|
||||||
|
self.0.as_path().is_empty() || self.0.as_path() == "/";
|
||||||
|
|
||||||
// match an initial /
|
// match an initial /
|
||||||
if let Some('/') = test.peek() {
|
if let Some('/') = test.peek() {
|
||||||
test.next();
|
test.next();
|
||||||
|
|
||||||
if !self.0.is_empty() {
|
if !self.0.as_path().is_empty() {
|
||||||
matched_len += 1;
|
matched_len += 1;
|
||||||
}
|
}
|
||||||
if self.0.starts_with('/') || self.0.is_empty() {
|
if self.0.as_path().starts_with('/') || self.0.as_path().is_empty()
|
||||||
|
{
|
||||||
this.next();
|
this.next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,14 +82,33 @@ impl PossibleRouteMatch for StaticSegment {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_path(&self, path: &mut Vec<PathSegment>) {
|
fn generate_path(&self, path: &mut Vec<PathSegment>) {
|
||||||
path.push(PathSegment::Static(self.0.into()))
|
path.push(PathSegment::Static(self.0.as_path().into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::AsPath;
|
||||||
|
|
||||||
use super::{PossibleRouteMatch, StaticSegment};
|
use super::{PossibleRouteMatch, StaticSegment};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum Paths {
|
||||||
|
Foo,
|
||||||
|
Bar,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsPath for Paths {
|
||||||
|
fn as_path(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Foo => "foo",
|
||||||
|
Bar => "bar",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use Paths::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn single_static_match() {
|
fn single_static_match() {
|
||||||
let path = "/foo";
|
let path = "/foo";
|
||||||
|
@ -89,6 +120,17 @@ mod tests {
|
||||||
assert!(params.is_empty());
|
assert!(params.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn single_static_match_on_enum() {
|
||||||
|
let path = "/foo";
|
||||||
|
let def = StaticSegment(Foo);
|
||||||
|
let matched = def.test(path).expect("couldn't match route");
|
||||||
|
assert_eq!(matched.matched(), "/foo");
|
||||||
|
assert_eq!(matched.remaining(), "");
|
||||||
|
let params = matched.params().collect::<Vec<_>>();
|
||||||
|
assert!(params.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn single_static_mismatch() {
|
fn single_static_mismatch() {
|
||||||
let path = "/foo";
|
let path = "/foo";
|
||||||
|
@ -96,6 +138,13 @@ mod tests {
|
||||||
assert!(def.test(path).is_none());
|
assert!(def.test(path).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn single_static_mismatch_on_enum() {
|
||||||
|
let path = "/foo";
|
||||||
|
let def = StaticSegment(Bar);
|
||||||
|
assert!(def.test(path).is_none());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn single_static_match_with_trailing_slash() {
|
fn single_static_match_with_trailing_slash() {
|
||||||
let path = "/foo/";
|
let path = "/foo/";
|
||||||
|
@ -107,6 +156,17 @@ mod tests {
|
||||||
assert!(params.is_empty());
|
assert!(params.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn single_static_match_with_trailing_slash_on_enum() {
|
||||||
|
let path = "/foo/";
|
||||||
|
let def = StaticSegment(Foo);
|
||||||
|
let matched = def.test(path).expect("couldn't match route");
|
||||||
|
assert_eq!(matched.matched(), "/foo");
|
||||||
|
assert_eq!(matched.remaining(), "/");
|
||||||
|
let params = matched.params().collect::<Vec<_>>();
|
||||||
|
assert!(params.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tuple_of_static_matches() {
|
fn tuple_of_static_matches() {
|
||||||
let path = "/foo/bar";
|
let path = "/foo/bar";
|
||||||
|
@ -118,6 +178,17 @@ mod tests {
|
||||||
assert!(params.is_empty());
|
assert!(params.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tuple_of_static_matches_on_enum() {
|
||||||
|
let path = "/foo/bar";
|
||||||
|
let def = (StaticSegment(Foo), StaticSegment(Bar));
|
||||||
|
let matched = def.test(path).expect("couldn't match route");
|
||||||
|
assert_eq!(matched.matched(), "/foo/bar");
|
||||||
|
assert_eq!(matched.remaining(), "");
|
||||||
|
let params = matched.params().collect::<Vec<_>>();
|
||||||
|
assert!(params.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tuple_static_mismatch() {
|
fn tuple_static_mismatch() {
|
||||||
let path = "/foo/baz";
|
let path = "/foo/baz";
|
||||||
|
@ -125,6 +196,13 @@ mod tests {
|
||||||
assert!(def.test(path).is_none());
|
assert!(def.test(path).is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tuple_static_mismatch_on_enum() {
|
||||||
|
let path = "/foo/baz";
|
||||||
|
let def = (StaticSegment(Foo), StaticSegment(Bar));
|
||||||
|
assert!(def.test(path).is_none());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn arbitrary_nesting_of_tuples_has_no_effect_on_matching() {
|
fn arbitrary_nesting_of_tuples_has_no_effect_on_matching() {
|
||||||
let path = "/foo/bar";
|
let path = "/foo/bar";
|
||||||
|
@ -142,4 +220,22 @@ mod tests {
|
||||||
let params = matched.params().collect::<Vec<_>>();
|
let params = matched.params().collect::<Vec<_>>();
|
||||||
assert!(params.is_empty());
|
assert!(params.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn arbitrary_nesting_of_tuples_has_no_effect_on_matching_on_enum() {
|
||||||
|
let path = "/foo/bar";
|
||||||
|
let def = (
|
||||||
|
(),
|
||||||
|
(StaticSegment(Foo)),
|
||||||
|
(),
|
||||||
|
((), ()),
|
||||||
|
StaticSegment(Bar),
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
let matched = def.test(path).expect("couldn't match route");
|
||||||
|
assert_eq!(matched.matched(), "/foo/bar");
|
||||||
|
assert_eq!(matched.remaining(), "");
|
||||||
|
let params = matched.params().collect::<Vec<_>>();
|
||||||
|
assert!(params.is_empty());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue