mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
initial stage for working nested route rendering
This commit is contained in:
parent
db4c1cb4b3
commit
13cccced06
15 changed files with 591 additions and 570 deletions
3
examples/router/.cargo/config.toml
Normal file
3
examples/router/.cargo/config.toml
Normal file
|
@ -0,0 +1,3 @@
|
|||
[unstable]
|
||||
build-std = ["std", "panic_abort", "core", "alloc"]
|
||||
build-std-features = ["panic_immediate_abort"]
|
|
@ -4,22 +4,24 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
opt-level = 'z'
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
panic = "abort"
|
||||
|
||||
[dependencies]
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
leptos = { path = "../../leptos", features = ["csr", "tracing"] }
|
||||
routing = { path = "../../routing", features = ["tracing"] }
|
||||
#leptos_router = { path = "../../router", features = ["csr"] }
|
||||
leptos = { path = "../../leptos", features = ["csr"] } #, "tracing"] }
|
||||
routing = { path = "../../routing" } #, features = ["tracing"] }
|
||||
#leptos_router = { path = "../../router", features = ["csr", "nightly"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
futures = "0.3"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
tracing-subscriber = "0.3.18"
|
||||
tracing-subscriber-wasm = "0.1.0"
|
||||
tracing = "0.1.40"
|
||||
#leptos_meta = { path = "../../meta", features = ["csr"] }
|
||||
#console_error_panic_hook = "0.1.7"
|
||||
#tracing-subscriber = "0.3.18"
|
||||
#tracing-subscriber-wasm = "0.1.0"
|
||||
#tracing = "0.1.40"
|
||||
#leptos_meta = { path = "../../meta", features = ["csr", "nightly"] }
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "0.3.0"
|
||||
|
|
|
@ -12,7 +12,8 @@ use leptos::{
|
|||
use log::{debug, info};
|
||||
use routing::{
|
||||
location::{BrowserUrl, Location},
|
||||
NestedRoute, ParamSegment, RouteData, Router, Routes, StaticSegment,
|
||||
MatchNestedRoutes, NestedRoute, ParamSegment, RouteData, Router, Routes,
|
||||
StaticSegment,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -20,7 +21,39 @@ struct ExampleContext(i32);
|
|||
|
||||
#[component]
|
||||
pub fn RouterExample() -> impl IntoView {
|
||||
info!("rendering <RouterExample/>");
|
||||
let router = Router::new(
|
||||
BrowserUrl::new().unwrap(),
|
||||
Routes::new((
|
||||
NestedRoute::new(StaticSegment(""), Home),
|
||||
NestedRoute::new(StaticSegment("notfound"), NotFount),
|
||||
NestedRoute::new(StaticSegment("about"), About),
|
||||
)),
|
||||
|| "This page could not be found.",
|
||||
);
|
||||
view! {
|
||||
<h3>"Leptos Router Bloat"</h3>
|
||||
|
||||
<nav>
|
||||
<a href="/">"Home"</a>
|
||||
" | "
|
||||
<a href="/about">"About"</a>
|
||||
</nav>
|
||||
<br />
|
||||
|
||||
<main>
|
||||
{router}
|
||||
// un-comment the following lines and build again
|
||||
// <Router>
|
||||
// <Routes>
|
||||
// <Route path="/" view=|cx| view! { cx, <Home /> } />
|
||||
// <Route path="/about" view=|cx| view! { cx, <About /> } />
|
||||
// <Route path="/*any" view=|cx| view! { cx, <NotFount /> } />
|
||||
// </Routes>
|
||||
// </Router>
|
||||
</main>
|
||||
}
|
||||
}
|
||||
/*info!("rendering <RouterExample/>");
|
||||
|
||||
// contexts are passed down through the route tree
|
||||
provide_context(ExampleContext(0));
|
||||
|
@ -28,39 +61,15 @@ pub fn RouterExample() -> impl IntoView {
|
|||
let router = Router::new(
|
||||
BrowserUrl::new().unwrap(),
|
||||
Routes::new((
|
||||
NestedRoute {
|
||||
segments: StaticSegment(""),
|
||||
children: (
|
||||
NestedRoute {
|
||||
segments: StaticSegment(""),
|
||||
children: (),
|
||||
data: (),
|
||||
view: |_: RouteData<Dom>| "Select a contact.",
|
||||
},
|
||||
// TODO: fix it so empty param doesn't match here, if we reverse the order of
|
||||
// these two
|
||||
NestedRoute {
|
||||
segments: ParamSegment("id"),
|
||||
children: (),
|
||||
data: (),
|
||||
view: Contact,
|
||||
},
|
||||
),
|
||||
data: (),
|
||||
view: ContactList,
|
||||
},
|
||||
NestedRoute {
|
||||
segments: StaticSegment("settings"),
|
||||
children: (),
|
||||
data: (),
|
||||
view: Settings,
|
||||
},
|
||||
NestedRoute {
|
||||
segments: StaticSegment("about"),
|
||||
children: (),
|
||||
data: (),
|
||||
view: About,
|
||||
},
|
||||
NestedRoute::new(StaticSegment("contacts"), ContactList).child((
|
||||
NestedRoute::new(StaticSegment(""), |_| "Select a contact."),
|
||||
// TODO: fix it so empty param doesn't match here, if we reverse the order of
|
||||
// these two
|
||||
NestedRoute::new(ParamSegment("id"), Contact),
|
||||
)),
|
||||
//NestedRoute::new(StaticSegment(""), ContactList),
|
||||
NestedRoute::new(StaticSegment("settings"), Settings),
|
||||
NestedRoute::new(StaticSegment("about"), About),
|
||||
)),
|
||||
|| "This page could not be found.",
|
||||
);
|
||||
|
@ -78,13 +87,13 @@ pub fn RouterExample() -> impl IntoView {
|
|||
<A href="settings">"Settings"</A>
|
||||
<A href="redirect-home">"Redirect to Home"</A>
|
||||
*/
|
||||
<a href="/">"Contacts"</a>
|
||||
<a href="about">"About"</a>
|
||||
<a href="settings">"Settings"</a>
|
||||
<a href="redirect-home">"Redirect to Home"</a>
|
||||
<a href="/contacts">"Contacts"</a>
|
||||
<a href="/about">"About"</a>
|
||||
<a href="/settings">"Settings"</a>
|
||||
<a href="/redirect-home">"Redirect to Home"</a>
|
||||
</nav>
|
||||
{router}
|
||||
/*<Router>
|
||||
<Router>
|
||||
<nav>
|
||||
// ordinary <a> elements can be used for client-side navigation
|
||||
// using <A> has two effects:
|
||||
|
@ -118,8 +127,20 @@ pub fn RouterExample() -> impl IntoView {
|
|||
/>
|
||||
</AnimatedRoutes>
|
||||
</main>
|
||||
</Router>*/
|
||||
</Router>
|
||||
}
|
||||
}*/
|
||||
|
||||
fn Home(data: RouteData<Dom>) -> impl IntoView {
|
||||
"Home Page"
|
||||
}
|
||||
|
||||
fn About(data: RouteData<Dom>) -> impl IntoView {
|
||||
"About Page"
|
||||
}
|
||||
|
||||
fn NotFount(data: RouteData<Dom>) -> impl IntoView {
|
||||
"Not Found!"
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -144,7 +165,7 @@ pub fn ContactRoutes() -> impl IntoView {
|
|||
}
|
||||
}*/
|
||||
|
||||
pub fn ContactList(route_data: RouteData<Dom>) -> impl IntoView {
|
||||
/*pub fn ContactList(route_data: RouteData<Dom>) -> impl IntoView {
|
||||
info!("rendering <ContactList/>");
|
||||
|
||||
// contexts are passed down through the route tree
|
||||
|
@ -314,4 +335,4 @@ pub fn Settings(route_data: RouteData<Dom>) -> impl IntoView {
|
|||
<pre>"This page is just a placeholder."</pre>
|
||||
</form>
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
use leptos::*;
|
||||
use router::*;
|
||||
use tracing_subscriber::fmt;
|
||||
use tracing_subscriber_wasm::MakeConsoleWriter;
|
||||
//use tracing_subscriber::fmt;
|
||||
//use tracing_subscriber_wasm::MakeConsoleWriter;
|
||||
|
||||
pub fn main() {
|
||||
fmt()
|
||||
/*fmt()
|
||||
.with_writer(
|
||||
MakeConsoleWriter::default()
|
||||
.map_trace_level_to(tracing::Level::DEBUG),
|
||||
)
|
||||
.without_time()
|
||||
.init();
|
||||
console_error_panic_hook::set_once();
|
||||
console_error_panic_hook::set_once();*/
|
||||
mount_to_body(|| view! { <RouterExample/> })
|
||||
}
|
||||
|
|
|
@ -93,9 +93,6 @@ impl Location for BrowserUrl {
|
|||
let navigate = {
|
||||
let url = self.url.clone();
|
||||
move |new_url, loc| {
|
||||
web_sys::console::log_1(&JsValue::from_str(
|
||||
"updating URL signal",
|
||||
));
|
||||
url.set(new_url);
|
||||
async move {
|
||||
Self::complete_navigation(&loc);
|
||||
|
|
|
@ -129,6 +129,7 @@ where
|
|||
|
||||
Box::new(move |ev: Event| {
|
||||
let ev = ev.unchecked_into::<MouseEvent>();
|
||||
let origin = window().location().origin()?;
|
||||
if ev.default_prevented()
|
||||
|| ev.button() != 0
|
||||
|| ev.meta_key()
|
||||
|
@ -168,23 +169,18 @@ where
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let base = window()
|
||||
.location()
|
||||
.origin()
|
||||
.map(Cow::Owned)
|
||||
.unwrap_or(Cow::Borrowed(BASE));
|
||||
let url = parse_with_base(href.as_str(), &base).unwrap();
|
||||
let url = parse_with_base(href.as_str(), &origin).unwrap();
|
||||
let path_name = unescape(&url.path);
|
||||
ev.prevent_default();
|
||||
|
||||
// let browser handle this event if it leaves our domain
|
||||
// or our base path
|
||||
if url.origin != window().location().origin().unwrap_or_default()
|
||||
if url.origin != origin
|
||||
|| (!router_base.is_empty()
|
||||
&& !path_name.is_empty()
|
||||
&& !path_name
|
||||
.to_lowercase()
|
||||
.starts_with(&router_base.to_lowercase()))
|
||||
// NOTE: the two `to_lowercase()` calls here added a total of about 14kb to
|
||||
// release binary size, for limited gain
|
||||
&& !path_name.starts_with(&*router_base))
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -203,8 +199,6 @@ where
|
|||
}
|
||||
});
|
||||
|
||||
ev.prevent_default();
|
||||
|
||||
let replace = Reflect::get(&a, &JsValue::from_str("replace"))
|
||||
.ok()
|
||||
.and_then(|value| value.as_bool())
|
||||
|
|
|
@ -4,6 +4,7 @@ use tachys::{renderer::Renderer, view::Render};
|
|||
|
||||
pub trait ChooseView<R>
|
||||
where
|
||||
Self: 'static,
|
||||
R: Renderer,
|
||||
{
|
||||
type Output: Render<R>;
|
||||
|
@ -13,7 +14,7 @@ where
|
|||
|
||||
impl<F, View, R> ChooseView<R> for F
|
||||
where
|
||||
F: Fn(RouteData<R>) -> View,
|
||||
F: Fn(RouteData<R>) -> View + 'static,
|
||||
View: Render<R>,
|
||||
R: Renderer,
|
||||
{
|
||||
|
@ -49,4 +50,35 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// TODO add other Either implementations
|
||||
macro_rules! tuples {
|
||||
($either:ident => $($ty:ident),*) => {
|
||||
impl<$($ty,)* Rndr> ChooseView<Rndr> for $either<$($ty,)*>
|
||||
where
|
||||
$($ty: ChooseView<Rndr>,)*
|
||||
Rndr: Renderer,
|
||||
{
|
||||
type Output = $either<$($ty::Output,)*>;
|
||||
|
||||
fn choose(self, route_data: RouteData<Rndr>) -> Self::Output {
|
||||
match self {
|
||||
$($either::$ty(f) => $either::$ty(f.choose(route_data)),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
tuples!(EitherOf3 => A, B, C);
|
||||
tuples!(EitherOf4 => A, B, C, D);
|
||||
tuples!(EitherOf5 => A, B, C, D, E);
|
||||
tuples!(EitherOf6 => A, B, C, D, E, F);
|
||||
tuples!(EitherOf7 => A, B, C, D, E, F, G);
|
||||
tuples!(EitherOf8 => A, B, C, D, E, F, G, H);
|
||||
tuples!(EitherOf9 => A, B, C, D, E, F, G, H, I);
|
||||
tuples!(EitherOf10 => A, B, C, D, E, F, G, H, I, J);
|
||||
tuples!(EitherOf11 => A, B, C, D, E, F, G, H, I, J, K);
|
||||
tuples!(EitherOf12 => A, B, C, D, E, F, G, H, I, J, K, L);
|
||||
tuples!(EitherOf13 => A, B, C, D, E, F, G, H, I, J, K, L, M);
|
||||
tuples!(EitherOf14 => A, B, C, D, E, F, G, H, I, J, K, L, M, N);
|
||||
tuples!(EitherOf15 => A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
|
||||
tuples!(EitherOf16 => A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use super::{PartialPathMatch, PathSegment};
|
||||
use std::borrow::Cow;
|
||||
mod param_segments;
|
||||
mod static_segment;
|
||||
mod tuples;
|
||||
|
@ -12,12 +13,12 @@ pub use static_segment::*;
|
|||
/// as subsequent segments of the URL and tries to match them all. For a "vertical"
|
||||
/// matching that sees a tuple as alternatives to one another, see [`RouteChild`](super::RouteChild).
|
||||
pub trait PossibleRouteMatch {
|
||||
type ParamsIter<'a>: IntoIterator<Item = (&'a str, &'a str)>;
|
||||
type ParamsIter: IntoIterator<Item = (Cow<'static, str>, String)>;
|
||||
|
||||
fn test<'a>(
|
||||
&self,
|
||||
path: &'a str,
|
||||
) -> Option<PartialPathMatch<'a, Self::ParamsIter<'a>>>;
|
||||
) -> Option<PartialPathMatch<'a, Self::ParamsIter>>;
|
||||
|
||||
fn generate_path(&self, path: &mut Vec<PathSegment>);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
use super::{PartialPathMatch, PathSegment, PossibleRouteMatch};
|
||||
use core::iter;
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct ParamSegment(pub &'static str);
|
||||
|
||||
impl PossibleRouteMatch for ParamSegment {
|
||||
type ParamsIter<'a> = iter::Once<(&'a str, &'a str)>;
|
||||
type ParamsIter = iter::Once<(Cow<'static, str>, String)>;
|
||||
|
||||
fn test<'a>(
|
||||
&self,
|
||||
path: &'a str,
|
||||
) -> Option<PartialPathMatch<'a, Self::ParamsIter<'a>>> {
|
||||
) -> Option<PartialPathMatch<'a, Self::ParamsIter>> {
|
||||
let mut matched_len = 0;
|
||||
let mut param_offset = 0;
|
||||
let mut param_len = 0;
|
||||
|
@ -34,8 +35,10 @@ impl PossibleRouteMatch for ParamSegment {
|
|||
}
|
||||
|
||||
let (matched, remaining) = path.split_at(matched_len);
|
||||
let param_value =
|
||||
iter::once((self.0, &path[param_offset..param_len + param_offset]));
|
||||
let param_value = iter::once((
|
||||
Cow::Borrowed(self.0),
|
||||
path[param_offset..param_len + param_offset].to_string(),
|
||||
));
|
||||
Some(PartialPathMatch::new(remaining, param_value, matched))
|
||||
}
|
||||
|
||||
|
@ -48,12 +51,12 @@ impl PossibleRouteMatch for ParamSegment {
|
|||
pub struct WildcardSegment(pub &'static str);
|
||||
|
||||
impl PossibleRouteMatch for WildcardSegment {
|
||||
type ParamsIter<'a> = iter::Once<(&'a str, &'a str)>;
|
||||
type ParamsIter = iter::Once<(Cow<'static, str>, String)>;
|
||||
|
||||
fn test<'a>(
|
||||
&self,
|
||||
path: &'a str,
|
||||
) -> Option<PartialPathMatch<'a, Self::ParamsIter<'a>>> {
|
||||
) -> Option<PartialPathMatch<'a, Self::ParamsIter>> {
|
||||
let mut matched_len = 0;
|
||||
let mut param_offset = 0;
|
||||
let mut param_len = 0;
|
||||
|
@ -70,8 +73,10 @@ impl PossibleRouteMatch for WildcardSegment {
|
|||
}
|
||||
|
||||
let (matched, remaining) = path.split_at(matched_len);
|
||||
let param_value =
|
||||
iter::once((self.0, &path[param_offset..param_len + param_offset]));
|
||||
let param_value = iter::once((
|
||||
Cow::Borrowed(self.0),
|
||||
path[param_offset..param_len + param_offset].to_string(),
|
||||
));
|
||||
Some(PartialPathMatch::new(remaining, param_value, matched))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
use super::{PartialPathMatch, PathSegment, PossibleRouteMatch};
|
||||
use core::iter;
|
||||
use std::borrow::Cow;
|
||||
|
||||
impl PossibleRouteMatch for () {
|
||||
type ParamsIter<'a> = iter::Empty<(&'a str, &'a str)>;
|
||||
type ParamsIter = iter::Empty<(Cow<'static, str>, String)>;
|
||||
|
||||
fn test<'a>(
|
||||
&self,
|
||||
path: &'a str,
|
||||
) -> Option<PartialPathMatch<'a, Self::ParamsIter<'a>>> {
|
||||
) -> Option<PartialPathMatch<'a, Self::ParamsIter>> {
|
||||
Some(PartialPathMatch::new(path, iter::empty(), ""))
|
||||
}
|
||||
|
||||
|
@ -18,12 +19,12 @@ impl PossibleRouteMatch for () {
|
|||
pub struct StaticSegment(pub &'static str);
|
||||
|
||||
impl PossibleRouteMatch for StaticSegment {
|
||||
type ParamsIter<'a> = iter::Empty<(&'a str, &'a str)>;
|
||||
type ParamsIter = iter::Empty<(Cow<'static, str>, String)>;
|
||||
|
||||
fn test<'a>(
|
||||
&self,
|
||||
path: &'a str,
|
||||
) -> Option<PartialPathMatch<'a, Self::ParamsIter<'a>>> {
|
||||
) -> Option<PartialPathMatch<'a, Self::ParamsIter>> {
|
||||
let mut matched_len = 0;
|
||||
let mut test = path.chars().peekable();
|
||||
let mut this = self.0.chars();
|
||||
|
|
|
@ -5,14 +5,14 @@ macro_rules! chain_types {
|
|||
($first:ty, $second:ty, ) => {
|
||||
Chain<
|
||||
$first,
|
||||
<<$second as PossibleRouteMatch>::ParamsIter<'a> as IntoIterator>::IntoIter
|
||||
<<$second as PossibleRouteMatch>::ParamsIter as IntoIterator>::IntoIter
|
||||
>
|
||||
};
|
||||
($first:ty, $second:ty, $($rest:ty,)+) => {
|
||||
chain_types!(
|
||||
Chain<
|
||||
$first,
|
||||
<<$second as PossibleRouteMatch>::ParamsIter<'a> as IntoIterator>::IntoIter,
|
||||
<<$second as PossibleRouteMatch>::ParamsIter as IntoIterator>::IntoIter,
|
||||
>,
|
||||
$($rest,)+
|
||||
)
|
||||
|
@ -27,9 +27,9 @@ macro_rules! tuples {
|
|||
$first: PossibleRouteMatch,
|
||||
$($ty: PossibleRouteMatch),*,
|
||||
{
|
||||
type ParamsIter<'a> = chain_types!(<<$first>::ParamsIter<'a> as IntoIterator>::IntoIter, $($ty,)*);
|
||||
type ParamsIter = chain_types!(<<$first>::ParamsIter as IntoIterator>::IntoIter, $($ty,)*);
|
||||
|
||||
fn test<'a>(&self, path: &'a str) -> Option<PartialPathMatch<'a, Self::ParamsIter<'a>>> {
|
||||
fn test<'a>(&self, path: &'a str) -> Option<PartialPathMatch<'a, Self::ParamsIter>> {
|
||||
let mut matched_len = 0;
|
||||
#[allow(non_snake_case)]
|
||||
let ($first, $($ty,)*) = &self;
|
||||
|
|
|
@ -10,7 +10,7 @@ pub use nested::*;
|
|||
use std::{borrow::Cow, marker::PhantomData};
|
||||
use tachys::{
|
||||
renderer::Renderer,
|
||||
view::{any_view::IntoAny, Render},
|
||||
view::{any_view::IntoAny, Render, RenderHtml},
|
||||
};
|
||||
pub use vertical::*;
|
||||
|
||||
|
@ -47,10 +47,7 @@ where
|
|||
Rndr: Renderer + 'static,
|
||||
Children: MatchNestedRoutes<Rndr>,
|
||||
{
|
||||
pub fn match_route<'a>(
|
||||
&'a self,
|
||||
path: &'a str,
|
||||
) -> Option<Children::Match<'a>> {
|
||||
pub fn match_route(&self, path: &str) -> Option<Children::Match> {
|
||||
let path = match &self.base {
|
||||
None => path,
|
||||
Some(base) => {
|
||||
|
@ -89,41 +86,40 @@ where
|
|||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct RouteMatchId(pub(crate) u8);
|
||||
|
||||
pub trait MatchInterface<'a, R>
|
||||
pub trait MatchInterface<R>
|
||||
where
|
||||
R: Renderer,
|
||||
R: Renderer + 'static,
|
||||
{
|
||||
type Params: IntoIterator<Item = (&'a str, &'a str)>;
|
||||
type Child: MatchInterface<'a, R>;
|
||||
type View: Render<R>;
|
||||
type Child: MatchInterface<R> + MatchParams + 'static;
|
||||
type View: Render<R> + RenderHtml<R> + 'static;
|
||||
|
||||
fn as_id(&self) -> RouteMatchId;
|
||||
|
||||
fn as_matched(&self) -> &str;
|
||||
|
||||
fn to_params(&self) -> Self::Params;
|
||||
|
||||
fn into_view_and_child(
|
||||
self,
|
||||
) -> (
|
||||
impl ChooseView<R, Output = Self::View> + 'a,
|
||||
Option<Self::Child>,
|
||||
);
|
||||
) -> (impl ChooseView<R, Output = Self::View>, Option<Self::Child>);
|
||||
}
|
||||
|
||||
pub trait MatchParams {
|
||||
type Params: IntoIterator<Item = (Cow<'static, str>, String)>;
|
||||
|
||||
fn to_params(&self) -> Self::Params;
|
||||
}
|
||||
|
||||
pub trait MatchNestedRoutes<R>
|
||||
where
|
||||
R: Renderer,
|
||||
R: Renderer + 'static,
|
||||
{
|
||||
type Data;
|
||||
type Match<'a>: MatchInterface<'a, R>
|
||||
where
|
||||
Self: 'a;
|
||||
type View;
|
||||
type Match: MatchInterface<R> + MatchParams;
|
||||
|
||||
fn match_nested<'a>(
|
||||
&'a self,
|
||||
path: &'a str,
|
||||
) -> (Option<(RouteMatchId, Self::Match<'a>)>, &str);
|
||||
) -> (Option<(RouteMatchId, Self::Match)>, &str);
|
||||
|
||||
fn generate_routes(
|
||||
&self,
|
||||
|
|
|
@ -2,10 +2,13 @@ use super::{
|
|||
MatchInterface, MatchNestedRoutes, PartialPathMatch, PathSegment,
|
||||
PossibleRouteMatch, RouteMatchId,
|
||||
};
|
||||
use crate::{ChooseView, RouteData};
|
||||
use crate::{ChooseView, MatchParams, RouteData};
|
||||
use core::{fmt, iter};
|
||||
use std::marker::PhantomData;
|
||||
use tachys::{renderer::Renderer, view::Render};
|
||||
use std::{borrow::Cow, marker::PhantomData};
|
||||
use tachys::{
|
||||
renderer::Renderer,
|
||||
view::{Render, RenderHtml},
|
||||
};
|
||||
|
||||
mod tuples;
|
||||
|
||||
|
@ -18,20 +21,58 @@ pub struct NestedRoute<Segments, Children, Data, ViewFn, R> {
|
|||
pub rndr: PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<Segments, ViewFn, R> NestedRoute<Segments, (), (), ViewFn, R> {
|
||||
pub fn new<View>(path: Segments, view: ViewFn) -> Self
|
||||
where
|
||||
ViewFn: Fn(RouteData<R>) -> View,
|
||||
R: Renderer,
|
||||
{
|
||||
Self {
|
||||
segments: path,
|
||||
children: (),
|
||||
data: (),
|
||||
view,
|
||||
rndr: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Segments, Data, ViewFn, R> NestedRoute<Segments, (), Data, ViewFn, R> {
|
||||
pub fn child<Children>(
|
||||
self,
|
||||
child: Children,
|
||||
) -> NestedRoute<Segments, Children, Data, ViewFn, R> {
|
||||
let Self {
|
||||
segments,
|
||||
data,
|
||||
view,
|
||||
rndr,
|
||||
..
|
||||
} = self;
|
||||
NestedRoute {
|
||||
segments,
|
||||
children: child,
|
||||
data,
|
||||
view,
|
||||
rndr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct NestedMatch<'a, ParamsIter, Child, ViewFn> {
|
||||
pub struct NestedMatch<ParamsIter, Child, ViewFn> {
|
||||
id: RouteMatchId,
|
||||
/// The portion of the full path matched only by this nested route.
|
||||
matched: &'a str,
|
||||
matched: String,
|
||||
/// The map of params matched only by this nested route.
|
||||
params: ParamsIter,
|
||||
/// The nested route.
|
||||
child: Child,
|
||||
view_fn: &'a ViewFn,
|
||||
view_fn: ViewFn,
|
||||
}
|
||||
|
||||
impl<'a, ParamsIter, Child, ViewFn> fmt::Debug
|
||||
for NestedMatch<'a, ParamsIter, Child, ViewFn>
|
||||
impl<ParamsIter, Child, ViewFn> fmt::Debug
|
||||
for NestedMatch<ParamsIter, Child, ViewFn>
|
||||
where
|
||||
ParamsIter: fmt::Debug,
|
||||
Child: fmt::Debug,
|
||||
|
@ -45,16 +86,27 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, ParamsIter, Child, ViewFn, Rndr> MatchInterface<'a, Rndr>
|
||||
for NestedMatch<'a, ParamsIter, Child, ViewFn>
|
||||
impl<ParamsIter, Child, ViewFn> MatchParams
|
||||
for NestedMatch<ParamsIter, Child, ViewFn>
|
||||
where
|
||||
Rndr: Renderer + 'static,
|
||||
ParamsIter: IntoIterator<Item = (&'a str, &'a str)> + Clone,
|
||||
Child: MatchInterface<'a, Rndr>,
|
||||
ViewFn: Fn(RouteData<Rndr>),
|
||||
ViewFn::Output: Render<Rndr>,
|
||||
ParamsIter: IntoIterator<Item = (Cow<'static, str>, String)> + Clone,
|
||||
{
|
||||
type Params = ParamsIter;
|
||||
|
||||
#[inline(always)]
|
||||
fn to_params(&self) -> Self::Params {
|
||||
self.params.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<ParamsIter, Child, ViewFn, View, Rndr> MatchInterface<Rndr>
|
||||
for NestedMatch<ParamsIter, Child, ViewFn>
|
||||
where
|
||||
Rndr: Renderer + 'static,
|
||||
Child: MatchInterface<Rndr> + MatchParams + 'static,
|
||||
ViewFn: Fn(RouteData<Rndr>) -> View + 'static,
|
||||
View: Render<Rndr> + RenderHtml<Rndr> + 'static,
|
||||
{
|
||||
type Child = Child;
|
||||
type View = ViewFn::Output;
|
||||
|
||||
|
@ -63,50 +115,44 @@ where
|
|||
}
|
||||
|
||||
fn as_matched(&self) -> &str {
|
||||
self.matched
|
||||
}
|
||||
|
||||
fn to_params(&self) -> Self::Params {
|
||||
self.params.clone()
|
||||
&self.matched
|
||||
}
|
||||
|
||||
fn into_view_and_child(
|
||||
self,
|
||||
) -> (
|
||||
impl ChooseView<Rndr, Output = Self::View> + 'a,
|
||||
impl ChooseView<Rndr, Output = Self::View>,
|
||||
Option<Self::Child>,
|
||||
) {
|
||||
(self.view_fn, Some(self.child))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, ParamsIter, Child, ViewFn> NestedMatch<'a, ParamsIter, Child, ViewFn> {
|
||||
pub fn matched(&self) -> &'a str {
|
||||
self.matched
|
||||
}
|
||||
}
|
||||
|
||||
impl<Segments, Children, Data, ViewFn, Rndr> MatchNestedRoutes<Rndr>
|
||||
impl<Segments, Children, Data, ViewFn, View, Rndr> MatchNestedRoutes<Rndr>
|
||||
for NestedRoute<Segments, Children, Data, ViewFn, Rndr>
|
||||
where
|
||||
Rndr: Renderer + 'static,
|
||||
Segments: PossibleRouteMatch,
|
||||
<<Segments as PossibleRouteMatch>::ParamsIter as IntoIterator>::IntoIter: Clone,
|
||||
Children: MatchNestedRoutes<Rndr>,
|
||||
for<'a> <Segments::ParamsIter<'a> as IntoIterator>::IntoIter: Clone,
|
||||
for <'a> <<Children::Match<'a> as MatchInterface<'a, Rndr>>::Params as IntoIterator>::IntoIter:
|
||||
Clone,
|
||||
ViewFn: Fn(RouteData<Rndr>),
|
||||
<<<Children as MatchNestedRoutes<Rndr>>::Match as MatchParams>::Params as IntoIterator>::IntoIter: Clone,
|
||||
Children::Match: MatchParams,
|
||||
Children: 'static,
|
||||
<Children::Match as MatchParams>::Params: Clone,
|
||||
ViewFn: Fn(RouteData<Rndr>) -> View + Clone + 'static,
|
||||
View: Render<Rndr> + RenderHtml<Rndr> + 'static,
|
||||
{
|
||||
type Data = Data;
|
||||
type Match<'a> = NestedMatch<'a, iter::Chain<
|
||||
<Segments::ParamsIter<'a> as IntoIterator>::IntoIter,
|
||||
<<Children::Match<'a> as MatchInterface<'a, Rndr>>::Params as IntoIterator>::IntoIter,
|
||||
>, Children::Match<'a>, ViewFn> where <Children as MatchNestedRoutes<Rndr>>::Match<'a>: 'a, ViewFn: 'a, Children: 'a, Segments: 'a, Data: 'a;
|
||||
type View = View;
|
||||
type Match = NestedMatch<iter::Chain<
|
||||
<Segments::ParamsIter as IntoIterator>::IntoIter,
|
||||
<<Children::Match as MatchParams>::Params as IntoIterator>::IntoIter,
|
||||
>, Children::Match, ViewFn>;
|
||||
|
||||
fn match_nested<'a>(
|
||||
&'a self,
|
||||
path: &'a str,
|
||||
) -> (Option<(RouteMatchId, Self::Match<'a>)>, &'a str) {
|
||||
) -> (Option<(RouteMatchId, Self::Match)>, &'a str) {
|
||||
self.segments
|
||||
.test(path)
|
||||
.and_then(
|
||||
|
@ -126,10 +172,10 @@ where
|
|||
id,
|
||||
NestedMatch {
|
||||
id,
|
||||
matched,
|
||||
matched: matched.to_string(),
|
||||
params: params.chain(inner.to_params()),
|
||||
child: inner,
|
||||
view_fn: &self.view,
|
||||
view_fn: self.view.clone(),
|
||||
},
|
||||
)),
|
||||
remaining,
|
||||
|
|
|
@ -1,14 +1,22 @@
|
|||
use super::{MatchInterface, MatchNestedRoutes, PathSegment, RouteMatchId};
|
||||
use crate::ChooseView;
|
||||
use crate::{ChooseView, MatchParams};
|
||||
use core::iter;
|
||||
use either_of::*;
|
||||
use std::borrow::Cow;
|
||||
use tachys::renderer::Renderer;
|
||||
|
||||
impl<'a, Rndr> MatchInterface<'a, Rndr> for ()
|
||||
impl MatchParams for () {
|
||||
type Params = iter::Empty<(Cow<'static, str>, String)>;
|
||||
|
||||
fn to_params(&self) -> Self::Params {
|
||||
iter::empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Rndr> MatchInterface<Rndr> for ()
|
||||
where
|
||||
Rndr: Renderer,
|
||||
Rndr: Renderer + 'static,
|
||||
{
|
||||
type Params = iter::Empty<(&'a str, &'a str)>;
|
||||
type Child = ();
|
||||
type View = ();
|
||||
|
||||
|
@ -20,14 +28,10 @@ where
|
|||
""
|
||||
}
|
||||
|
||||
fn to_params(&self) -> Self::Params {
|
||||
iter::empty()
|
||||
}
|
||||
|
||||
fn into_view_and_child(
|
||||
self,
|
||||
) -> (
|
||||
impl ChooseView<Rndr, Output = Self::View> + 'a,
|
||||
impl ChooseView<Rndr, Output = Self::View>,
|
||||
Option<Self::Child>,
|
||||
) {
|
||||
((), None)
|
||||
|
@ -36,15 +40,16 @@ where
|
|||
|
||||
impl<Rndr> MatchNestedRoutes<Rndr> for ()
|
||||
where
|
||||
Rndr: Renderer,
|
||||
Rndr: Renderer + 'static,
|
||||
{
|
||||
type Data = ();
|
||||
type Match<'a> = ();
|
||||
type View = ();
|
||||
type Match = ();
|
||||
|
||||
fn match_nested<'a>(
|
||||
&self,
|
||||
path: &'a str,
|
||||
) -> (Option<(RouteMatchId, Self::Match<'a>)>, &'a str) {
|
||||
) -> (Option<(RouteMatchId, Self::Match)>, &'a str) {
|
||||
(Some((RouteMatchId(0), ())), path)
|
||||
}
|
||||
|
||||
|
@ -55,12 +60,22 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, A, Rndr> MatchInterface<'a, Rndr> for (A,)
|
||||
impl<A> MatchParams for (A,)
|
||||
where
|
||||
A: MatchInterface<'a, Rndr>,
|
||||
Rndr: Renderer,
|
||||
A: MatchParams,
|
||||
{
|
||||
type Params = A::Params;
|
||||
|
||||
fn to_params(&self) -> Self::Params {
|
||||
self.0.to_params()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, Rndr> MatchInterface<Rndr> for (A,)
|
||||
where
|
||||
A: MatchInterface<Rndr>,
|
||||
Rndr: Renderer + 'static,
|
||||
{
|
||||
type Child = A::Child;
|
||||
type View = A::View;
|
||||
|
||||
|
@ -72,14 +87,10 @@ where
|
|||
self.0.as_matched()
|
||||
}
|
||||
|
||||
fn to_params(&self) -> Self::Params {
|
||||
self.0.to_params()
|
||||
}
|
||||
|
||||
fn into_view_and_child(
|
||||
self,
|
||||
) -> (
|
||||
impl ChooseView<Rndr, Output = Self::View> + 'a,
|
||||
impl ChooseView<Rndr, Output = Self::View>,
|
||||
Option<Self::Child>,
|
||||
) {
|
||||
self.0.into_view_and_child()
|
||||
|
@ -89,15 +100,16 @@ where
|
|||
impl<A, Rndr> MatchNestedRoutes<Rndr> for (A,)
|
||||
where
|
||||
A: MatchNestedRoutes<Rndr>,
|
||||
Rndr: Renderer,
|
||||
Rndr: Renderer + 'static,
|
||||
{
|
||||
type Data = A::Data;
|
||||
type Match<'a> = A::Match<'a> where A: 'a;
|
||||
type View = A::View;
|
||||
type Match = A::Match;
|
||||
|
||||
fn match_nested<'a>(
|
||||
&'a self,
|
||||
path: &'a str,
|
||||
) -> (Option<(RouteMatchId, Self::Match<'a>)>, &'a str) {
|
||||
) -> (Option<(RouteMatchId, Self::Match)>, &'a str) {
|
||||
self.0.match_nested(path)
|
||||
}
|
||||
|
||||
|
@ -108,16 +120,30 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, A, B, Rndr> MatchInterface<'a, Rndr> for Either<A, B>
|
||||
impl<A, B> MatchParams for Either<A, B>
|
||||
where
|
||||
Rndr: Renderer,
|
||||
A: MatchInterface<'a, Rndr>,
|
||||
B: MatchInterface<'a, Rndr>,
|
||||
A: MatchParams,
|
||||
B: MatchParams,
|
||||
{
|
||||
type Params = Either<
|
||||
<A::Params as IntoIterator>::IntoIter,
|
||||
<B::Params as IntoIterator>::IntoIter,
|
||||
>;
|
||||
|
||||
fn to_params(&self) -> Self::Params {
|
||||
match self {
|
||||
Either::Left(i) => Either::Left(i.to_params().into_iter()),
|
||||
Either::Right(i) => Either::Right(i.to_params().into_iter()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, Rndr> MatchInterface<Rndr> for Either<A, B>
|
||||
where
|
||||
Rndr: Renderer + 'static,
|
||||
A: MatchInterface<Rndr>,
|
||||
B: MatchInterface<Rndr>,
|
||||
{
|
||||
type Child = Either<A::Child, B::Child>;
|
||||
type View = Either<A::View, B::View>;
|
||||
|
||||
|
@ -135,17 +161,10 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn to_params(&self) -> Self::Params {
|
||||
match self {
|
||||
Either::Left(i) => Either::Left(i.to_params().into_iter()),
|
||||
Either::Right(i) => Either::Right(i.to_params().into_iter()),
|
||||
}
|
||||
}
|
||||
|
||||
fn into_view_and_child(
|
||||
self,
|
||||
) -> (
|
||||
impl ChooseView<Rndr, Output = Self::View> + 'a,
|
||||
impl ChooseView<Rndr, Output = Self::View>,
|
||||
Option<Self::Child>,
|
||||
) {
|
||||
match self {
|
||||
|
@ -168,12 +187,13 @@ where
|
|||
Rndr: Renderer + 'static,
|
||||
{
|
||||
type Data = (A::Data, B::Data);
|
||||
type Match<'a> = Either<A::Match<'a>, B::Match<'a>> where A: 'a, B: 'a;
|
||||
type View = Either<A::View, B::View>;
|
||||
type Match = Either<A::Match, B::Match>;
|
||||
|
||||
fn match_nested<'a>(
|
||||
&'a self,
|
||||
path: &'a str,
|
||||
) -> (Option<(RouteMatchId, Self::Match<'a>)>, &'a str) {
|
||||
) -> (Option<(RouteMatchId, Self::Match)>, &'a str) {
|
||||
#[allow(non_snake_case)]
|
||||
let (A, B) = &self;
|
||||
if let (Some((id, matched)), remaining) = A.match_nested(path) {
|
||||
|
@ -213,15 +233,26 @@ macro_rules! chain_generated {
|
|||
|
||||
macro_rules! tuples {
|
||||
($either:ident => $($ty:ident = $count:expr),*) => {
|
||||
impl<'a, Rndr, $($ty,)*> MatchInterface<'a, Rndr> for $either <$($ty,)*>
|
||||
impl<'a, $($ty,)*> MatchParams for $either <$($ty,)*>
|
||||
where
|
||||
Rndr: Renderer + 'static,
|
||||
$($ty: MatchInterface<'a, Rndr>),*,
|
||||
$($ty::Child: 'a),*,
|
||||
$($ty: MatchParams),*,
|
||||
{
|
||||
type Params = $either<$(
|
||||
<$ty::Params as IntoIterator>::IntoIter,
|
||||
)*>;
|
||||
|
||||
fn to_params(&self) -> Self::Params {
|
||||
match self {
|
||||
$($either::$ty(i) => $either::$ty(i.to_params().into_iter()),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Rndr, $($ty,)*> MatchInterface<Rndr> for $either <$($ty,)*>
|
||||
where
|
||||
Rndr: Renderer + 'static,
|
||||
$($ty: MatchInterface<Rndr>),*,
|
||||
{
|
||||
type Child = $either<$($ty::Child,)*>;
|
||||
type View = $either<$($ty::View,)*>;
|
||||
|
||||
|
@ -237,35 +268,31 @@ macro_rules! tuples {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_params(&self) -> Self::Params {
|
||||
fn into_view_and_child(
|
||||
self,
|
||||
) -> (
|
||||
impl ChooseView<Rndr, Output = Self::View>,
|
||||
Option<Self::Child>,
|
||||
) {
|
||||
match self {
|
||||
$($either::$ty(i) => $either::$ty(i.to_params().into_iter()),)*
|
||||
}
|
||||
}
|
||||
|
||||
fn into_child(self) -> Option<Self::Child> {
|
||||
Some(match self {
|
||||
$($either::$ty(i) => $either::$ty(i.into_child()?),)*
|
||||
})
|
||||
}
|
||||
|
||||
fn to_view(&self) -> impl ChooseView<Rndr, Output = Self::View> {
|
||||
match self {
|
||||
$($either::$ty(i) => $either::$ty(i.to_view()),)*
|
||||
$($either::$ty(i) => {
|
||||
let (view, child) = i.into_view_and_child();
|
||||
($either::$ty(view), child.map($either::$ty))
|
||||
})*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Rndr, $($ty),*> MatchNestedRoutes<'a, Rndr> for ($($ty,)*)
|
||||
impl<Rndr, $($ty),*> MatchNestedRoutes<Rndr> for ($($ty,)*)
|
||||
where
|
||||
Rndr: Renderer + 'static,
|
||||
$($ty: MatchNestedRoutes<'a, Rndr>),*,
|
||||
$($ty::Match: 'a),*,
|
||||
$($ty: MatchNestedRoutes<Rndr>),*,
|
||||
{
|
||||
type Data = ($($ty::Data,)*);
|
||||
type View = $either<$($ty::View,)*>;
|
||||
type Match = $either<$($ty::Match,)*>;
|
||||
|
||||
fn match_nested(&'a self, path: &'a str) -> (Option<(RouteMatchId, Self::Match)>, &'a str) {
|
||||
fn match_nested<'a>(&'a self, path: &'a str) -> (Option<(RouteMatchId, Self::Match)>, &'a str) {
|
||||
#[allow(non_snake_case)]
|
||||
|
||||
let ($($ty,)*) = &self;
|
||||
|
@ -290,9 +317,9 @@ macro_rules! tuples {
|
|||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
||||
tuples!(EitherOf3 => A = 0, B = 1, C = 2);
|
||||
tuples!(EitherOf4 => A = 0, B = 1, C = 2, D = 3);
|
||||
/*tuples!(EitherOf4 => A = 0, B = 1, C = 2, D = 3);
|
||||
tuples!(EitherOf5 => A = 0, B = 1, C = 2, D = 3, E = 4);
|
||||
tuples!(EitherOf6 => A = 0, B = 1, C = 2, D = 3, E = 4, F = 5);
|
||||
tuples!(EitherOf7 => A = 0, B = 1, C = 2, D = 3, E = 4, F = 5, G = 6);
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
MatchInterface, MatchNestedRoutes, PossibleRouteMatch, RouteMatchId,
|
||||
Routes,
|
||||
},
|
||||
ChooseView, Params,
|
||||
ChooseView, MatchParams, Params,
|
||||
};
|
||||
use core::marker::PhantomData;
|
||||
use either_of::*;
|
||||
|
@ -45,6 +45,7 @@ where
|
|||
Rndr: Renderer,
|
||||
FallbackFn: Fn() -> Fallback,
|
||||
{
|
||||
#[inline(always)]
|
||||
pub fn new(
|
||||
location: Loc,
|
||||
routes: Routes<Children, Rndr>,
|
||||
|
@ -58,6 +59,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn new_with_base(
|
||||
base: impl Into<Cow<'static, str>>,
|
||||
location: Loc,
|
||||
|
@ -99,13 +101,19 @@ where
|
|||
FallbackFn: Fn() -> Fallback + 'static,
|
||||
Fallback: Render<Rndr>,
|
||||
Children: MatchNestedRoutes<Rndr> + 'static,
|
||||
//for<'a> <Children::Match<'a> as MatchInterface<Rndr, View = View>>,
|
||||
/*View: Render<Rndr> + IntoAny<Rndr> + 'static,
|
||||
View::State: 'static,*/
|
||||
Fallback::State: 'static,
|
||||
Rndr: Renderer + 'static,
|
||||
{
|
||||
type State =
|
||||
RenderEffect<EitherState<(), <Fallback as Render<Rndr>>::State, Rndr>>;
|
||||
type State = RenderEffect<
|
||||
EitherState<
|
||||
<NestedRouteView<Children::Match, Rndr> as Render<Rndr>>::State,
|
||||
<Fallback as Render<Rndr>>::State,
|
||||
Rndr,
|
||||
>,
|
||||
>;
|
||||
type FallibleState = ();
|
||||
|
||||
fn build(self) -> Self::State {
|
||||
|
@ -130,33 +138,32 @@ where
|
|||
if let Some(new_match) = new_match {
|
||||
match &mut prev.state {
|
||||
Either::Left(prev) => {
|
||||
// TODO!
|
||||
//nested_rebuild(&outer_owner, prev, new_match);
|
||||
}
|
||||
Either::Right(_) => {
|
||||
/*Either::<_, Fallback>::Left(NestedRouteView::new(
|
||||
&outer_owner,
|
||||
new_match,
|
||||
))
|
||||
.rebuild(&mut prev);*/
|
||||
Either::<_, Fallback>::Left(
|
||||
NestedRouteView::create(
|
||||
&outer_owner,
|
||||
new_match,
|
||||
),
|
||||
)
|
||||
.rebuild(&mut prev);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*Either::<NestedRouteView<View, Rndr>, _>::Right((self
|
||||
.fallback)(
|
||||
))
|
||||
.rebuild(&mut prev);*/
|
||||
Either::<NestedRouteView<Children::Match, Rndr>, _>::Right(
|
||||
(self.fallback)(),
|
||||
)
|
||||
.rebuild(&mut prev);
|
||||
}
|
||||
prev
|
||||
} else {
|
||||
match new_match {
|
||||
Some(matched) =>
|
||||
/*Either::Left(NestedRouteView::new(
|
||||
Some(matched) => Either::Left(NestedRouteView::create(
|
||||
&outer_owner,
|
||||
matched,
|
||||
))*/
|
||||
{
|
||||
Either::Left(())
|
||||
}
|
||||
)),
|
||||
_ => Either::Right((self.fallback)()),
|
||||
}
|
||||
.build()
|
||||
|
@ -178,65 +185,155 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/*fn nested_rebuild<NewMatch, R>(
|
||||
outer_owner: &Owner,
|
||||
current: &mut NestedRouteState<
|
||||
<<NewMatch::View as ChooseView<R>>::Output as Render<R>>::State,
|
||||
>,
|
||||
new: NewMatch,
|
||||
) where
|
||||
NewMatch: MatchInterface<R>,
|
||||
NewMatch::View: ChooseView<R>,
|
||||
<NewMatch::View as ChooseView<R>>::Output: Render<R> + IntoAny<R> + 'static,
|
||||
NewMatch::Child: std::fmt::Debug,
|
||||
R: Renderer + 'static,
|
||||
{
|
||||
// if the new match is a different branch of the nested route tree from the current one, we can
|
||||
// just rebuild the view starting here: everything underneath it will change
|
||||
if new.as_id() != current.id {
|
||||
// TODO provide params + matched via context?
|
||||
let new_view = NestedRouteView::new(outer_owner, new);
|
||||
let prev_owner = std::mem::replace(&mut current.owner, new_view.owner);
|
||||
current.id = new_view.id;
|
||||
current.params = new_view.params;
|
||||
current.matched = new_view.matched;
|
||||
current
|
||||
.owner
|
||||
.with(|| new_view.view.rebuild(&mut current.view));
|
||||
|
||||
// TODO is this the right place to drop the old Owner?
|
||||
drop(prev_owner);
|
||||
} else {
|
||||
// otherwise, we should recurse to the children of the current view, and the new match
|
||||
//nested_rebuild(current.as_child_mut(), new.as_child())
|
||||
}
|
||||
|
||||
// update params, in case they're different
|
||||
// TODO
|
||||
}*/
|
||||
|
||||
pub struct NestedRouteView<View, R>
|
||||
pub struct NestedRouteView<Matcher, R>
|
||||
where
|
||||
R: Renderer,
|
||||
Matcher: MatchInterface<R>,
|
||||
R: Renderer + 'static,
|
||||
{
|
||||
id: RouteMatchId,
|
||||
owner: Owner,
|
||||
params: ArcRwSignal<Params>,
|
||||
matched: ArcRwSignal<String>,
|
||||
view: View,
|
||||
rndr: PhantomData<R>,
|
||||
view: Matcher::View,
|
||||
//child: Option<Box<dyn FnOnce() -> NestedRouteView<Matcher::Child, R>>>,
|
||||
ty: PhantomData<(Matcher, R)>,
|
||||
}
|
||||
|
||||
impl<View, R> NestedRouteView<View, R>
|
||||
impl<Matcher, Rndr> NestedRouteView<Matcher, Rndr>
|
||||
where
|
||||
Matcher: MatchInterface<Rndr> + MatchParams,
|
||||
Matcher::Child: 'static,
|
||||
Matcher::View: 'static,
|
||||
Rndr: Renderer + 'static,
|
||||
{
|
||||
pub fn create(outer_owner: &Owner, route_match: Matcher) -> Self {
|
||||
let id = route_match.as_id();
|
||||
let owner = outer_owner.child();
|
||||
let params = ArcRwSignal::new(
|
||||
route_match
|
||||
.to_params()
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.to_string(), v.to_string()))
|
||||
.collect(),
|
||||
);
|
||||
let matched = ArcRwSignal::new(route_match.as_matched().to_string());
|
||||
/*let (view, child) = route_match.into_view_and_child();
|
||||
let child = child.map(|child| {
|
||||
let owner = owner.clone();
|
||||
Box::new(move || NestedRouteView::create(&owner, child))
|
||||
as Box<dyn FnOnce() -> NestedRouteView<Matcher::Child, Rndr>>
|
||||
});*/
|
||||
let view = build_nested(route_match);
|
||||
|
||||
Self {
|
||||
id,
|
||||
owner,
|
||||
params,
|
||||
matched,
|
||||
view,
|
||||
ty: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NestedRouteState<Matcher, Rndr>
|
||||
where
|
||||
Matcher: MatchInterface<Rndr>,
|
||||
Rndr: Renderer + 'static,
|
||||
{
|
||||
id: RouteMatchId,
|
||||
owner: Owner,
|
||||
params: ArcRwSignal<Params>,
|
||||
matched: ArcRwSignal<String>,
|
||||
view: <Matcher::View as Render<Rndr>>::State,
|
||||
//child: Option<Box<NestedRouteState<Matcher::Child, Rndr>>>,
|
||||
}
|
||||
|
||||
// TODO: also build a Vec<(RouteMatchId, ArcRwSignal<Params>)>
|
||||
// when we rebuild, at each level,
|
||||
// if the route IDs don't match, then replace with new
|
||||
// if they do match, then just update params
|
||||
fn build_nested<Match, R>(route_match: Match) -> Match::View
|
||||
where
|
||||
Match: MatchInterface<R>,
|
||||
R: Renderer,
|
||||
{
|
||||
let (view, child) = route_match.into_view_and_child();
|
||||
let outlet = move || child.map(|child| build_nested(child)).into_any();
|
||||
let data = RouteData {
|
||||
params: { ArcMemo::new(move |_| Params::new()) },
|
||||
outlet: Box::new(outlet),
|
||||
};
|
||||
view.choose(data)
|
||||
}
|
||||
|
||||
impl<Matcher, R> Render<R> for NestedRouteView<Matcher, R>
|
||||
where
|
||||
Matcher: MatchInterface<R>,
|
||||
Matcher::View: Sized + 'static,
|
||||
R: Renderer + 'static,
|
||||
{
|
||||
type State = NestedRouteState<Matcher, R>;
|
||||
type FallibleState = ();
|
||||
|
||||
fn build(self) -> Self::State {
|
||||
NestedRouteState {
|
||||
id: self.id,
|
||||
owner: self.owner,
|
||||
params: self.params,
|
||||
matched: self.matched,
|
||||
view: self.view.build(), //child: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn try_build(self) -> tachys::error::Result<Self::FallibleState> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn try_rebuild(
|
||||
self,
|
||||
state: &mut Self::FallibleState,
|
||||
) -> tachys::error::Result<()> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Matcher, R> Mountable<R> for NestedRouteState<Matcher, R>
|
||||
where
|
||||
Matcher: MatchInterface<R>,
|
||||
R: Renderer + 'static,
|
||||
{
|
||||
fn unmount(&mut self) {
|
||||
self.view.unmount();
|
||||
}
|
||||
|
||||
fn mount(&mut self, parent: &R::Element, marker: Option<&R::Node>) {
|
||||
self.view.mount(parent, marker);
|
||||
}
|
||||
|
||||
fn insert_before_this(
|
||||
&self,
|
||||
parent: &R::Element,
|
||||
child: &mut dyn Mountable<R>,
|
||||
) -> bool {
|
||||
self.view.insert_before_this(parent, child)
|
||||
}
|
||||
}
|
||||
|
||||
/*impl<View, R> NestedRouteView<View, R>
|
||||
where
|
||||
R: Renderer + 'static,
|
||||
{
|
||||
pub fn new<Matcher>(outer_owner: &Owner, route_match: Matcher) -> Self
|
||||
where
|
||||
Matcher: for<'a> MatchInterface<'a, R, View = View> + 'static,
|
||||
for<'a> <Matcher as MatchInterface<'a, R>>::View:
|
||||
Matcher: for<'a> MatchInterface<R, View = View> + 'static,
|
||||
for<'a> <Matcher as MatchInterface<R>>::View:
|
||||
ChooseView<R, Output = View>,
|
||||
for<'a> <Matcher as MatchInterface<'a, R>>::Child: std::fmt::Debug,
|
||||
for<'a> <Matcher as MatchInterface<R>>::Child: std::fmt::Debug,
|
||||
View: IntoAny<R> + 'static,
|
||||
{
|
||||
let params = ArcRwSignal::new(
|
||||
|
@ -281,83 +378,104 @@ where
|
|||
rndr: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
impl<R, View> Render<R> for NestedRouteView<View, R>
|
||||
where
|
||||
View: Render<R>,
|
||||
R: Renderer,
|
||||
/*fn nested_rebuild<NewMatch, R>(
|
||||
outer_owner: &Owner,
|
||||
current: &mut NestedRouteState<
|
||||
<<NewMatch::View as ChooseView<R>>::Output as Render<R>>::State,
|
||||
>,
|
||||
new: NewMatch,
|
||||
) where
|
||||
NewMatch: MatchInterface<R>,
|
||||
NewMatch::View: ChooseView<R>,
|
||||
<NewMatch::View as ChooseView<R>>::Output: Render<R> + IntoAny<R> + 'static,
|
||||
NewMatch::Child: std::fmt::Debug,
|
||||
R: Renderer + 'static,
|
||||
{
|
||||
type State = NestedRouteState<View::State>;
|
||||
type FallibleState = ();
|
||||
// if the new match is a different branch of the nested route tree from the current one, we can
|
||||
// just rebuild the view starting here: everything underneath it will change
|
||||
if new.as_id() != current.id {
|
||||
// TODO provide params + matched via context?
|
||||
let new_view = NestedRouteView::new(outer_owner, new);
|
||||
let prev_owner = std::mem::replace(&mut current.owner, new_view.owner);
|
||||
current.id = new_view.id;
|
||||
current.params = new_view.params;
|
||||
current.matched = new_view.matched;
|
||||
current
|
||||
.owner
|
||||
.with(|| new_view.view.rebuild(&mut current.view));
|
||||
|
||||
fn build(self) -> Self::State {
|
||||
let NestedRouteView {
|
||||
// TODO is this the right place to drop the old Owner?
|
||||
drop(prev_owner);
|
||||
} else {
|
||||
// otherwise, we should recurse to the children of the current view, and the new match
|
||||
//nested_rebuild(current.as_child_mut(), new.as_child())
|
||||
}
|
||||
|
||||
// update params, in case they're different
|
||||
// TODO
|
||||
}*/
|
||||
|
||||
/*impl<View, R> NestedRouteView<View, R>
|
||||
where
|
||||
R: Renderer + 'static,
|
||||
{
|
||||
pub fn new<Matcher>(outer_owner: &Owner, route_match: Matcher) -> Self
|
||||
where
|
||||
Matcher: for<'a> MatchInterface<R, View = View> + 'static,
|
||||
for<'a> <Matcher as MatchInterface<R>>::View:
|
||||
ChooseView<R, Output = View>,
|
||||
for<'a> <Matcher as MatchInterface<R>>::Child: std::fmt::Debug,
|
||||
View: IntoAny<R> + 'static,
|
||||
{
|
||||
let params = ArcRwSignal::new(
|
||||
route_match
|
||||
.to_params()
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k.to_string(), v.to_string()))
|
||||
.collect(),
|
||||
);
|
||||
let matched = ArcRwSignal::new(route_match.as_matched().to_string());
|
||||
let id = route_match.as_id();
|
||||
let (view, child) = route_match.into_view_and_child();
|
||||
let route_data = RouteData {
|
||||
params: {
|
||||
let params = params.clone();
|
||||
ArcMemo::new(move |_| params.get())
|
||||
},
|
||||
outlet: Box::new({
|
||||
move || {
|
||||
child
|
||||
.map(|child| {
|
||||
// TODO nest the next child and use real params
|
||||
/*let params = child.to_params().into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect::<Params>();
|
||||
let route_data = RouteData {
|
||||
params: ArcMemo::new(move |_| {
|
||||
params.clone()
|
||||
}),
|
||||
outlet: Box::new(|| ().into_any())
|
||||
};*/
|
||||
format!("{child:?}")
|
||||
})
|
||||
.into_any()
|
||||
}
|
||||
}),
|
||||
};
|
||||
NestedRouteView {
|
||||
id,
|
||||
owner,
|
||||
owner: outer_owner.child(),
|
||||
params,
|
||||
matched,
|
||||
view,
|
||||
rndr,
|
||||
} = self;
|
||||
NestedRouteState {
|
||||
id,
|
||||
owner,
|
||||
params,
|
||||
matched,
|
||||
view: view.build(),
|
||||
view: view.choose(route_data),
|
||||
rndr: PhantomData,
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn try_build(self) -> tachys::error::Result<Self::FallibleState> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn try_rebuild(
|
||||
self,
|
||||
state: &mut Self::FallibleState,
|
||||
) -> tachys::error::Result<()> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NestedRouteState<ViewState> {
|
||||
id: RouteMatchId,
|
||||
owner: Owner,
|
||||
params: ArcRwSignal<Params>,
|
||||
matched: ArcRwSignal<String>,
|
||||
view: ViewState,
|
||||
}
|
||||
|
||||
impl<ViewState, R> Mountable<R> for NestedRouteState<ViewState>
|
||||
trait RouteView<R>: for<'a> MatchInterface<R>
|
||||
where
|
||||
ViewState: Mountable<R>,
|
||||
R: Renderer,
|
||||
{
|
||||
fn unmount(&mut self) {
|
||||
self.view.unmount();
|
||||
}
|
||||
|
||||
fn mount(&mut self, parent: &R::Element, marker: Option<&R::Node>) {
|
||||
self.view.mount(parent, marker);
|
||||
}
|
||||
|
||||
fn insert_before_this(
|
||||
&self,
|
||||
parent: &R::Element,
|
||||
child: &mut dyn Mountable<R>,
|
||||
) -> bool {
|
||||
self.view.insert_before_this(parent, child)
|
||||
}
|
||||
}
|
||||
|
||||
trait RouteView<R>: for<'a> MatchInterface<'a, R>
|
||||
where
|
||||
R: Renderer,
|
||||
R: Renderer + 'static,
|
||||
{
|
||||
type RouteViewChild: RouteView<R>;
|
||||
type RouteView: Render<R>;
|
||||
|
@ -365,23 +483,16 @@ where
|
|||
fn into_child(self) -> Option<Self::RouteViewChild>;
|
||||
}
|
||||
|
||||
impl<Rndr, Loc, FallbackFn, Fallback, Children, View> RenderHtml<Rndr>
|
||||
impl<Rndr, Loc, FallbackFn, Fallback, Children> RenderHtml<Rndr>
|
||||
for Router<Rndr, Loc, Children, FallbackFn>
|
||||
where
|
||||
Loc: Location,
|
||||
FallbackFn: Fn() -> Fallback + 'static,
|
||||
Fallback: RenderHtml<Rndr>,
|
||||
Children: MatchNestedRoutes<Rndr> + 'static,
|
||||
for<'a> <<Children as MatchNestedRoutes<Rndr>>::Match<'a> as MatchInterface<
|
||||
'a,
|
||||
Rndr,
|
||||
>>::View: ChooseView<Rndr, Output = View>,
|
||||
for<'a> <<Children as MatchNestedRoutes<Rndr>>::Match<'a> as MatchInterface<
|
||||
'a,
|
||||
Rndr,
|
||||
>>::Child: std::fmt::Debug,
|
||||
View: Render<Rndr> + IntoAny<Rndr> + 'static,
|
||||
View::State: 'static,
|
||||
Children::View: RenderHtml<Rndr>,
|
||||
/*View: Render<Rndr> + IntoAny<Rndr> + 'static,
|
||||
View::State: 'static,*/
|
||||
Fallback::State: 'static,
|
||||
Rndr: Renderer + 'static,
|
||||
{
|
||||
|
@ -408,11 +519,10 @@ where
|
|||
FallbackFn: Fn() -> Fallback,
|
||||
Fallback: Render<Rndr>,
|
||||
Children: MatchNestedRoutes<Rndr>,
|
||||
for<'a> <<Children as MatchNestedRoutes<Rndr>>::Match<'a> as MatchInterface<
|
||||
'a,
|
||||
<<Children as MatchNestedRoutes<Rndr>>::Match as MatchInterface<
|
||||
Rndr,
|
||||
>>::View: ChooseView<Rndr, Output = View>,
|
||||
Rndr: Renderer,
|
||||
Rndr: Renderer + 'static,
|
||||
Router<Rndr, Loc, Children, FallbackFn>: RenderHtml<Rndr>,
|
||||
{
|
||||
type Output<SomeNewAttr: Attribute<Rndr>> = Self;
|
||||
|
@ -437,217 +547,3 @@ where
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! tuples {
|
||||
($either:ident => $($ty:ident),*) => {
|
||||
paste::paste! {
|
||||
impl<Rndr, $($ty, [<Fn $ty>],)*> ChooseView<Rndr> for $either<$([<Fn $ty>],)*>
|
||||
where
|
||||
Rndr: Renderer,
|
||||
$([<Fn $ty>]: Fn(RouteData<Rndr>) -> $ty,)*
|
||||
$($ty: Render<Rndr>,)*
|
||||
{
|
||||
type Output = $either<$($ty,)*>;
|
||||
|
||||
fn choose(self, route_data: RouteData<Rndr>) -> Self::Output {
|
||||
match self {
|
||||
$($either::$ty(f) => $either::$ty(f(route_data)),)*
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tuples!(EitherOf3 => A, B, C);
|
||||
tuples!(EitherOf4 => A, B, C, D);
|
||||
tuples!(EitherOf5 => A, B, C, D, E);
|
||||
tuples!(EitherOf6 => A, B, C, D, E, F);
|
||||
tuples!(EitherOf7 => A, B, C, D, E, F, G);
|
||||
tuples!(EitherOf8 => A, B, C, D, E, F, G, H);
|
||||
tuples!(EitherOf9 => A, B, C, D, E, F, G, H, I);
|
||||
tuples!(EitherOf10 => A, B, C, D, E, F, G, H, I, J);
|
||||
tuples!(EitherOf11 => A, B, C, D, E, F, G, H, I, J, K);
|
||||
tuples!(EitherOf12 => A, B, C, D, E, F, G, H, I, J, K, L);
|
||||
tuples!(EitherOf13 => A, B, C, D, E, F, G, H, I, J, K, L, M);
|
||||
tuples!(EitherOf14 => A, B, C, D, E, F, G, H, I, J, K, L, M, N);
|
||||
tuples!(EitherOf15 => A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
|
||||
tuples!(EitherOf16 => A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
|
||||
/*
|
||||
impl<Rndr, Loc, Fal, Children> RenderHtml<Rndr>
|
||||
for Router<Rndr, Loc, Children, Fal>
|
||||
where
|
||||
Self: FallbackOrViewHtml,
|
||||
Rndr: Renderer,
|
||||
Loc: Location,
|
||||
Children: PossibleRouteMatch,
|
||||
<Self as FallbackOrView>::Output: RenderHtml<Rndr>,
|
||||
Rndr::Element: Clone,
|
||||
Rndr::Node: Clone,
|
||||
{
|
||||
const MIN_LENGTH: usize = <Self as FallbackOrViewHtml>::MIN_LENGTH;
|
||||
|
||||
fn to_html_with_buf(self, buf: &mut String, position: &mut Position) {
|
||||
if RouteList::is_generating() {
|
||||
let routes = RouteList::default();
|
||||
RouteList::register(routes);
|
||||
} else {
|
||||
self.fallback_or_view().1.to_html_with_buf(buf, position);
|
||||
}
|
||||
}
|
||||
|
||||
fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
|
||||
self,
|
||||
buf: &mut StreamBuilder,
|
||||
position: &mut Position,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
if RouteList::is_generating() {
|
||||
let routes = RouteList::default();
|
||||
RouteList::register(routes);
|
||||
} else {
|
||||
self.fallback_or_view()
|
||||
.1
|
||||
.to_html_async_with_buf::<OUT_OF_ORDER>(buf, position);
|
||||
}
|
||||
}
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(
|
||||
self,
|
||||
cursor: &Cursor<Rndr>,
|
||||
position: &PositionState,
|
||||
) -> Self::State {
|
||||
self.fallback_or_view()
|
||||
.1
|
||||
.hydrate::<FROM_SERVER>(cursor, position)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FallbackOrView {
|
||||
type Output;
|
||||
|
||||
fn fallback_or_view(&self) -> (&'static str, Self::Output);
|
||||
|
||||
fn generate_route_list(&self, route_list: &mut RouteList);
|
||||
}
|
||||
|
||||
pub trait FallbackOrViewHtml: FallbackOrView {
|
||||
const MIN_LENGTH: usize;
|
||||
}
|
||||
|
||||
impl<Rndr, Loc, FallbackFn, Fal> FallbackOrView
|
||||
for Router<Rndr, Loc, (), FallbackFn>
|
||||
where
|
||||
Rndr: Renderer,
|
||||
Loc: Location,
|
||||
FallbackFn: Fn() -> Fal,
|
||||
Fal: Render<Rndr>,
|
||||
{
|
||||
type Output = Fal;
|
||||
|
||||
fn fallback_or_view(&self) -> (&'static str, Self::Output) {
|
||||
("Fal", (self.fallback)())
|
||||
}
|
||||
|
||||
fn generate_route_list(&self, _route_list: &mut RouteList) {}
|
||||
}
|
||||
|
||||
impl<Rndr, Loc, FallbackFn, Fal> FallbackOrViewHtml
|
||||
for Router<Rndr, Loc, (), FallbackFn>
|
||||
where
|
||||
Rndr: Renderer,
|
||||
Loc: Location,
|
||||
FallbackFn: Fn() -> Fal,
|
||||
Fal: RenderHtml<Rndr>,
|
||||
Rndr::Element: Clone,
|
||||
Rndr::Node: Clone,
|
||||
{
|
||||
const MIN_LENGTH: usize = Fal::MIN_LENGTH;
|
||||
}
|
||||
|
||||
impl<Rndr, Loc, FallbackFn, Fal, APat, AViewFn, AView, AChildren> FallbackOrView
|
||||
for Router<
|
||||
Rndr,
|
||||
Loc,
|
||||
RouteDefinition<Rndr, APat, AViewFn, AChildren>,
|
||||
FallbackFn,
|
||||
>
|
||||
where
|
||||
Rndr: Renderer,
|
||||
Loc: Location,
|
||||
APat: RouteMatch,
|
||||
AViewFn: Fn(MatchedRoute) -> AView,
|
||||
AView: Render<Rndr>,
|
||||
FallbackFn: Fn() -> Fal,
|
||||
Fal: Render<Rndr>,
|
||||
{
|
||||
type Output = Either<Fal, AView>;
|
||||
|
||||
fn fallback_or_view(&self) -> (&'static str, Self::Output) {
|
||||
match self.location.try_to_url() {
|
||||
Ok(url) => {
|
||||
if self.routes.path.matches(&url.pathname) {
|
||||
let PartialPathMatch {
|
||||
params,
|
||||
matched,
|
||||
remaining,
|
||||
} = self.routes.path.test(&url.pathname).unwrap();
|
||||
if remaining.is_empty() {
|
||||
let matched = MatchedRoute {
|
||||
params,
|
||||
matched,
|
||||
search_params: url.search_params.clone(),
|
||||
};
|
||||
return (
|
||||
"Route",
|
||||
Either::Right(self.routes.view(matched)),
|
||||
);
|
||||
}
|
||||
}
|
||||
("Fal", Either::Left(self.fallback()))
|
||||
}
|
||||
Err(e) => {
|
||||
#[cfg(feature = "tracing")]
|
||||
{
|
||||
tracing::error!(
|
||||
"Error converting location into URL: {e:?}"
|
||||
);
|
||||
}
|
||||
("Fal", Either::Left(self.fallback()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_route_list(&self, route_list: &mut RouteList) {
|
||||
let mut path = Vec::new();
|
||||
self.routes.path.generate_path(&mut path);
|
||||
route_list.push(RouteListing::from_path(path));
|
||||
}
|
||||
}
|
||||
|
||||
impl<Rndr, Loc, FallbackFn, Fal, APat, AViewFn, AView, AChildren>
|
||||
FallbackOrViewHtml
|
||||
for Router<
|
||||
Rndr,
|
||||
Loc,
|
||||
RouteDefinition<Rndr, APat, AViewFn, AChildren>,
|
||||
FallbackFn,
|
||||
>
|
||||
where
|
||||
Rndr: Renderer,
|
||||
Loc: Location,
|
||||
APat: RouteMatch,
|
||||
AViewFn: Fn(MatchedRoute) -> AView,
|
||||
AView: RenderHtml<Rndr>,
|
||||
FallbackFn: Fn() -> Fal,
|
||||
Fal: RenderHtml<Rndr>,
|
||||
Rndr::Element: Clone,
|
||||
Rndr::Node: Clone,
|
||||
{
|
||||
const MIN_LENGTH: usize = if Fal::MIN_LENGTH < AView::MIN_LENGTH {
|
||||
Fal::MIN_LENGTH
|
||||
} else {
|
||||
AView::MIN_LENGTH
|
||||
};
|
||||
}*/
|
||||
|
|
Loading…
Reference in a new issue