This commit is contained in:
Greg Johnston 2024-03-08 12:57:32 -05:00
parent 9cdd8cac15
commit db4c1cb4b3
8 changed files with 223 additions and 186 deletions

View File

@ -7,7 +7,7 @@ version.workspace = true
any_spawner = { workspace = true } any_spawner = { workspace = true }
either_of = { workspace = true } either_of = { workspace = true }
reactive_graph = { workspace = true } reactive_graph = { workspace = true }
tachys = { workspace = true } tachys = { workspace = true, features = ["reactive_graph"] }
url = "2" url = "2"
js-sys = { version = "0.3" } js-sys = { version = "0.3" }
wasm-bindgen = { version = "0.2" } wasm-bindgen = { version = "0.2" }

View File

@ -0,0 +1,52 @@
use crate::RouteData;
use either_of::*;
use tachys::{renderer::Renderer, view::Render};
pub trait ChooseView<R>
where
R: Renderer,
{
type Output: Render<R>;
fn choose(self, route_data: RouteData<R>) -> Self::Output;
}
impl<F, View, R> ChooseView<R> for F
where
F: Fn(RouteData<R>) -> View,
View: Render<R>,
R: Renderer,
{
type Output = View;
fn choose(self, route_data: RouteData<R>) -> Self::Output {
self(route_data)
}
}
impl<R> ChooseView<R> for ()
where
R: Renderer,
{
type Output = ();
fn choose(self, _route_data: RouteData<R>) -> Self::Output {}
}
impl<A, B, Rndr> ChooseView<Rndr> for Either<A, B>
where
A: ChooseView<Rndr>,
B: ChooseView<Rndr>,
Rndr: Renderer,
{
type Output = Either<A::Output, B::Output>;
fn choose(self, route_data: RouteData<Rndr>) -> Self::Output {
match self {
Either::Left(f) => Either::Left(f.choose(route_data)),
Either::Right(f) => Either::Right(f.choose(route_data)),
}
}
}
// TODO add other Either implementations

View File

@ -84,7 +84,6 @@ impl PossibleRouteMatch for WildcardSegment {
mod tests { mod tests {
use super::PossibleRouteMatch; use super::PossibleRouteMatch;
use crate::{ParamSegment, StaticSegment, WildcardSegment}; use crate::{ParamSegment, StaticSegment, WildcardSegment};
use alloc::vec::Vec;
#[test] #[test]
fn single_param_match() { fn single_param_match() {

View File

@ -76,7 +76,6 @@ impl PossibleRouteMatch for StaticSegment {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{PossibleRouteMatch, StaticSegment}; use super::{PossibleRouteMatch, StaticSegment};
use alloc::vec::Vec;
#[test] #[test]
fn single_static_match() { fn single_static_match() {

View File

@ -1,4 +1,6 @@
mod choose_view;
mod path_segment; mod path_segment;
pub use choose_view::*;
pub use path_segment::*; pub use path_segment::*;
mod horizontal; mod horizontal;
mod nested; mod nested;
@ -40,12 +42,15 @@ impl<Children, Rndr> Routes<Children, Rndr> {
} }
} }
impl<'a, Children, Rndr> Routes<Children, Rndr> impl<Children, Rndr> Routes<Children, Rndr>
where where
Rndr: Renderer + 'static, Rndr: Renderer + 'static,
Children: MatchNestedRoutes<'a, Rndr>, Children: MatchNestedRoutes<Rndr>,
{ {
pub fn match_route(&'a self, path: &'a str) -> Option<Children::Match> { pub fn match_route<'a>(
&'a self,
path: &'a str,
) -> Option<Children::Match<'a>> {
let path = match &self.base { let path = match &self.base {
None => path, None => path,
Some(base) => { Some(base) => {
@ -72,10 +77,10 @@ where
} }
pub fn generate_routes( pub fn generate_routes(
&'a self, &self,
) -> ( ) -> (
Option<&str>, Option<&str>,
impl IntoIterator<Item = Vec<PathSegment>> + 'a, impl IntoIterator<Item = Vec<PathSegment>> + '_,
) { ) {
(self.base.as_deref(), self.children.generate_routes()) (self.base.as_deref(), self.children.generate_routes())
} }
@ -98,22 +103,27 @@ where
fn to_params(&self) -> Self::Params; fn to_params(&self) -> Self::Params;
fn into_child(self) -> Option<Self::Child>; fn into_view_and_child(
self,
fn to_view(&self) -> impl Fn() -> View; ) -> (
impl ChooseView<R, Output = Self::View> + 'a,
Option<Self::Child>,
);
} }
pub trait MatchNestedRoutes<'a, R> pub trait MatchNestedRoutes<R>
where where
R: Renderer, R: Renderer,
{ {
type Data; type Data;
type Match: MatchInterface<'a, R>; type Match<'a>: MatchInterface<'a, R>
where
Self: 'a;
fn match_nested( fn match_nested<'a>(
&'a self, &'a self,
path: &'a str, path: &'a str,
) -> (Option<(RouteMatchId, Self::Match)>, &'a str); ) -> (Option<(RouteMatchId, Self::Match<'a>)>, &str);
fn generate_routes( fn generate_routes(
&self, &self,
@ -124,14 +134,17 @@ where
mod tests { mod tests {
use super::{NestedRoute, ParamSegment, Routes}; use super::{NestedRoute, ParamSegment, Routes};
use crate::{MatchInterface, PathSegment, StaticSegment, WildcardSegment}; use crate::{MatchInterface, PathSegment, StaticSegment, WildcardSegment};
use std::marker::PhantomData;
use tachys::renderer::dom::Dom;
#[test] #[test]
pub fn matches_single_root_route() { pub fn matches_single_root_route() {
let routes = Routes::new(NestedRoute { let routes = Routes::<_, Dom>::new(NestedRoute {
segments: StaticSegment("/"), segments: StaticSegment("/"),
children: (), children: (),
data: (), data: (),
view: || (), view: |_| (),
rndr: PhantomData,
}); });
let matched = routes.match_route("/"); let matched = routes.match_route("/");
assert!(matched.is_some()); assert!(matched.is_some());
@ -151,10 +164,12 @@ mod tests {
segments: (StaticSegment("author"), StaticSegment("contact")), segments: (StaticSegment("author"), StaticSegment("contact")),
children: (), children: (),
data: (), data: (),
view: "Contact Me", view: |_| "Contact Me",
rndr: PhantomData,
}, },
data: (), data: (),
view: "Home", view: |_| "Home",
rndr: PhantomData,
}); });
// route generation // route generation
@ -188,9 +203,11 @@ mod tests {
children: (), children: (),
data: (), data: (),
view: "Contact Me", view: "Contact Me",
rndr: PhantomData,
}, },
data: (), data: (),
view: "Home", view: "Home",
rndr: PhantomData,
}); });
let matched = routes.match_route("/"); let matched = routes.match_route("/");
assert!(matched.is_none()); assert!(matched.is_none());
@ -207,16 +224,19 @@ mod tests {
children: (), children: (),
data: (), data: (),
view: || (), view: || (),
rndr: PhantomData,
}, },
NestedRoute { NestedRoute {
segments: StaticSegment("about"), segments: StaticSegment("about"),
children: (), children: (),
data: (), data: (),
view: || (), view: || (),
rndr: PhantomData,
}, },
), ),
data: (), data: (),
view: || (), view: || (),
rndr: PhantomData,
}, },
NestedRoute { NestedRoute {
segments: StaticSegment("/blog"), segments: StaticSegment("/blog"),
@ -226,16 +246,19 @@ mod tests {
children: (), children: (),
data: (), data: (),
view: || (), view: || (),
rndr: PhantomData,
}, },
NestedRoute { NestedRoute {
segments: (StaticSegment("post"), ParamSegment("id")), segments: (StaticSegment("post"), ParamSegment("id")),
children: (), children: (),
data: (), data: (),
view: || (), view: || (),
rndr: PhantomData,
}, },
), ),
data: (), data: (),
view: || (), view: || (),
rndr: PhantomData,
}, },
)); ));
@ -289,16 +312,19 @@ mod tests {
children: (), children: (),
data: (), data: (),
view: || (), view: || (),
rndr: PhantomData,
}, },
NestedRoute { NestedRoute {
segments: StaticSegment("about"), segments: StaticSegment("about"),
children: (), children: (),
data: (), data: (),
view: || (), view: || (),
rndr: PhantomData,
}, },
), ),
data: (), data: (),
view: || (), view: || (),
rndr: PhantomData,
}, },
NestedRoute { NestedRoute {
segments: StaticSegment("/blog"), segments: StaticSegment("/blog"),
@ -308,12 +334,14 @@ mod tests {
children: (), children: (),
data: (), data: (),
view: || (), view: || (),
rndr: PhantomData,
}, },
NestedRoute { NestedRoute {
segments: StaticSegment("category"), segments: StaticSegment("category"),
children: (), children: (),
data: (), data: (),
view: || (), view: || (),
rndr: PhantomData,
}, },
NestedRoute { NestedRoute {
segments: ( segments: (
@ -323,10 +351,12 @@ mod tests {
children: (), children: (),
data: (), data: (),
view: || (), view: || (),
rndr: PhantomData,
}, },
), ),
data: (), data: (),
view: || (), view: || (),
rndr: PhantomData,
}, },
NestedRoute { NestedRoute {
segments: ( segments: (
@ -336,6 +366,7 @@ mod tests {
children: (), children: (),
data: (), data: (),
view: || (), view: || (),
rndr: PhantomData,
}, },
), ),
"/portfolio", "/portfolio",

View File

@ -2,21 +2,24 @@ use super::{
MatchInterface, MatchNestedRoutes, PartialPathMatch, PathSegment, MatchInterface, MatchNestedRoutes, PartialPathMatch, PathSegment,
PossibleRouteMatch, RouteMatchId, PossibleRouteMatch, RouteMatchId,
}; };
use crate::{ChooseView, RouteData};
use core::{fmt, iter}; use core::{fmt, iter};
use tachys::renderer::Renderer; use std::marker::PhantomData;
use tachys::{renderer::Renderer, view::Render};
mod tuples; mod tuples;
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct NestedRoute<Segments, Children, Data, View> { pub struct NestedRoute<Segments, Children, Data, ViewFn, R> {
pub segments: Segments, pub segments: Segments,
pub children: Children, pub children: Children,
pub data: Data, pub data: Data,
pub view: View, pub view: ViewFn,
pub rndr: PhantomData<R>,
} }
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
pub struct NestedMatch<'a, ParamsIter, Child, ViewFn, View> { pub struct NestedMatch<'a, ParamsIter, Child, ViewFn> {
id: RouteMatchId, id: RouteMatchId,
/// The portion of the full path matched only by this nested route. /// The portion of the full path matched only by this nested route.
matched: &'a str, matched: &'a str,
@ -24,12 +27,11 @@ pub struct NestedMatch<'a, ParamsIter, Child, ViewFn, View> {
params: ParamsIter, params: ParamsIter,
/// The nested route. /// The nested route.
child: Child, child: Child,
view_fn: ViewFn, view_fn: &'a ViewFn,
view: View
} }
impl<'a, ParamsIter, Child, View> fmt::Debug impl<'a, ParamsIter, Child, ViewFn> fmt::Debug
for NestedMatch<'a, ParamsIter, Child, View> for NestedMatch<'a, ParamsIter, Child, ViewFn>
where where
ParamsIter: fmt::Debug, ParamsIter: fmt::Debug,
Child: fmt::Debug, Child: fmt::Debug,
@ -43,16 +45,18 @@ where
} }
} }
impl<'a, ParamsIter, Child, ViewFn, View, Rndr> MatchInterface<'a, Rndr> impl<'a, ParamsIter, Child, ViewFn, Rndr> MatchInterface<'a, Rndr>
for NestedMatch<'a, ParamsIter, Child, ViewFn, View> for NestedMatch<'a, ParamsIter, Child, ViewFn>
where where
Rndr: Renderer + 'static, Rndr: Renderer + 'static,
ParamsIter: IntoIterator<Item = (&'a str, &'a str)> + Clone, ParamsIter: IntoIterator<Item = (&'a str, &'a str)> + Clone,
Child: MatchInterface<'a, Rndr>, Child: MatchInterface<'a, Rndr>,
ViewFn: Fn(RouteData<Rndr>),
ViewFn::Output: Render<Rndr>,
{ {
type Params = ParamsIter; type Params = ParamsIter;
type Child = Child; type Child = Child;
type View = View; type View = ViewFn::Output;
fn as_id(&self) -> RouteMatchId { fn as_id(&self) -> RouteMatchId {
self.id self.id
@ -66,43 +70,43 @@ where
self.params.clone() self.params.clone()
} }
fn into_child(self) -> Option<Self::Child> { fn into_view_and_child(
Some(self.child) self,
} ) -> (
impl ChooseView<Rndr, Output = Self::View> + 'a,
fn to_view(&self) -> Self::ViewFn { Option<Self::Child>,
self.view ) {
(self.view_fn, Some(self.child))
} }
} }
impl<'a, ParamsIter, Child, View> NestedMatch<'a, ParamsIter, Child, View> { impl<'a, ParamsIter, Child, ViewFn> NestedMatch<'a, ParamsIter, Child, ViewFn> {
pub fn matched(&self) -> &'a str { pub fn matched(&self) -> &'a str {
self.matched self.matched
} }
} }
impl<'a, Segments, Children, Data, View, Rndr> MatchNestedRoutes<'a, Rndr> impl<Segments, Children, Data, ViewFn, Rndr> MatchNestedRoutes<Rndr>
for NestedRoute<Segments, Children, Data, View> for NestedRoute<Segments, Children, Data, ViewFn, Rndr>
where where
Rndr: Renderer + 'static, Rndr: Renderer + 'static,
Segments: PossibleRouteMatch, Segments: PossibleRouteMatch,
Children: MatchNestedRoutes<'a, Rndr>, Children: MatchNestedRoutes<Rndr>,
<Segments::ParamsIter<'a> as IntoIterator>::IntoIter: Clone, for<'a> <Segments::ParamsIter<'a> as IntoIterator>::IntoIter: Clone,
<<Children::Match as MatchInterface<'a, Rndr>>::Params as IntoIterator>::IntoIter: for <'a> <<Children::Match<'a> as MatchInterface<'a, Rndr>>::Params as IntoIterator>::IntoIter:
Clone, Clone,
Children: 'a, ViewFn: Fn(RouteData<Rndr>),
View: 'a,
{ {
type Data = Data; type Data = Data;
type Match = NestedMatch<'a, iter::Chain< type Match<'a> = NestedMatch<'a, iter::Chain<
<Segments::ParamsIter<'a> as IntoIterator>::IntoIter, <Segments::ParamsIter<'a> as IntoIterator>::IntoIter,
<<Children::Match as MatchInterface<'a, Rndr>>::Params as IntoIterator>::IntoIter, <<Children::Match<'a> as MatchInterface<'a, Rndr>>::Params as IntoIterator>::IntoIter,
>, Children::Match, View>; >, Children::Match<'a>, ViewFn> where <Children as MatchNestedRoutes<Rndr>>::Match<'a>: 'a, ViewFn: 'a, Children: 'a, Segments: 'a, Data: 'a;
fn match_nested( fn match_nested<'a>(
&'a self, &'a self,
path: &'a str, path: &'a str,
) -> (Option<(RouteMatchId, Self::Match)>, &'a str) { ) -> (Option<(RouteMatchId, Self::Match<'a>)>, &'a str) {
self.segments self.segments
.test(path) .test(path)
.and_then( .and_then(
@ -125,7 +129,7 @@ where
matched, matched,
params: params.chain(inner.to_params()), params: params.chain(inner.to_params()),
child: inner, child: inner,
view: &self.view, view_fn: &self.view,
}, },
)), )),
remaining, remaining,

View File

@ -1,4 +1,5 @@
use super::{MatchInterface, MatchNestedRoutes, PathSegment, RouteMatchId}; use super::{MatchInterface, MatchNestedRoutes, PathSegment, RouteMatchId};
use crate::ChooseView;
use core::iter; use core::iter;
use either_of::*; use either_of::*;
use tachys::renderer::Renderer; use tachys::renderer::Renderer;
@ -23,24 +24,27 @@ where
iter::empty() iter::empty()
} }
fn into_child(self) -> Option<Self::Child> { fn into_view_and_child(
None self,
) -> (
impl ChooseView<Rndr, Output = Self::View> + 'a,
Option<Self::Child>,
) {
((), None)
} }
fn to_view(&self) -> Self::View {}
} }
impl<'a, Rndr> MatchNestedRoutes<'a, Rndr> for () impl<Rndr> MatchNestedRoutes<Rndr> for ()
where where
Rndr: Renderer, Rndr: Renderer,
{ {
type Data = (); type Data = ();
type Match = (); type Match<'a> = ();
fn match_nested( fn match_nested<'a>(
&self, &self,
path: &'a str, path: &'a str,
) -> (Option<(RouteMatchId, Self::Match)>, &'a str) { ) -> (Option<(RouteMatchId, Self::Match<'a>)>, &'a str) {
(Some((RouteMatchId(0), ())), path) (Some((RouteMatchId(0), ())), path)
} }
@ -72,27 +76,28 @@ where
self.0.to_params() self.0.to_params()
} }
fn into_child(self) -> Option<Self::Child> { fn into_view_and_child(
self.0.into_child() self,
} ) -> (
impl ChooseView<Rndr, Output = Self::View> + 'a,
fn to_view(&self) -> Self::View { Option<Self::Child>,
self.0.to_view() ) {
self.0.into_view_and_child()
} }
} }
impl<'a, A, Rndr> MatchNestedRoutes<'a, Rndr> for (A,) impl<A, Rndr> MatchNestedRoutes<Rndr> for (A,)
where where
A: MatchNestedRoutes<'a, Rndr>, A: MatchNestedRoutes<Rndr>,
Rndr: Renderer, Rndr: Renderer,
{ {
type Data = A::Data; type Data = A::Data;
type Match = A::Match; type Match<'a> = A::Match<'a> where A: 'a;
fn match_nested( fn match_nested<'a>(
&'a self, &'a self,
path: &'a str, path: &'a str,
) -> (Option<(RouteMatchId, Self::Match)>, &'a str) { ) -> (Option<(RouteMatchId, Self::Match<'a>)>, &'a str) {
self.0.match_nested(path) self.0.match_nested(path)
} }
@ -105,7 +110,7 @@ where
impl<'a, A, B, Rndr> MatchInterface<'a, Rndr> for Either<A, B> impl<'a, A, B, Rndr> MatchInterface<'a, Rndr> for Either<A, B>
where where
Rndr: Renderer + 'a, Rndr: Renderer,
A: MatchInterface<'a, Rndr>, A: MatchInterface<'a, Rndr>,
B: MatchInterface<'a, Rndr>, B: MatchInterface<'a, Rndr>,
{ {
@ -137,34 +142,38 @@ where
} }
} }
fn into_child(self) -> Option<Self::Child> { fn into_view_and_child(
Some(match self { self,
Either::Left(i) => Either::Left(i.into_child()?), ) -> (
Either::Right(i) => Either::Right(i.into_child()?), impl ChooseView<Rndr, Output = Self::View> + 'a,
}) Option<Self::Child>,
} ) {
fn to_view(&self) -> Self::View {
match self { match self {
Either::Left(i) => Either::Left(i.to_view()), Either::Left(i) => {
Either::Right(i) => Either::Right(i.to_view()), let (view, child) = i.into_view_and_child();
(Either::Left(view), child.map(Either::Left))
}
Either::Right(i) => {
let (view, child) = i.into_view_and_child();
(Either::Right(view), child.map(Either::Right))
}
} }
} }
} }
impl<'a, A, B, Rndr> MatchNestedRoutes<'a, Rndr> for (A, B) impl<A, B, Rndr> MatchNestedRoutes<Rndr> for (A, B)
where where
A: MatchNestedRoutes<'a, Rndr>, A: MatchNestedRoutes<Rndr>,
B: MatchNestedRoutes<'a, Rndr>, B: MatchNestedRoutes<Rndr>,
Rndr: Renderer + 'static, Rndr: Renderer + 'static,
{ {
type Data = (A::Data, B::Data); type Data = (A::Data, B::Data);
type Match = Either<A::Match, B::Match>; type Match<'a> = Either<A::Match<'a>, B::Match<'a>> where A: 'a, B: 'a;
fn match_nested( fn match_nested<'a>(
&'a self, &'a self,
path: &'a str, path: &'a str,
) -> (Option<(RouteMatchId, Self::Match)>, &'a str) { ) -> (Option<(RouteMatchId, Self::Match<'a>)>, &'a str) {
#[allow(non_snake_case)] #[allow(non_snake_case)]
let (A, B) = &self; let (A, B) = &self;
if let (Some((id, matched)), remaining) = A.match_nested(path) { if let (Some((id, matched)), remaining) = A.match_nested(path) {
@ -209,7 +218,6 @@ macro_rules! tuples {
Rndr: Renderer + 'static, Rndr: Renderer + 'static,
$($ty: MatchInterface<'a, Rndr>),*, $($ty: MatchInterface<'a, Rndr>),*,
$($ty::Child: 'a),*, $($ty::Child: 'a),*,
$($ty::View: 'a),*,
{ {
type Params = $either<$( type Params = $either<$(
<$ty::Params as IntoIterator>::IntoIter, <$ty::Params as IntoIterator>::IntoIter,
@ -241,7 +249,7 @@ macro_rules! tuples {
}) })
} }
fn to_view(&self) -> Self::View { fn to_view(&self) -> impl ChooseView<Rndr, Output = Self::View> {
match self { match self {
$($either::$ty(i) => $either::$ty(i.to_view()),)* $($either::$ty(i) => $either::$ty(i.to_view()),)*
} }
@ -282,7 +290,7 @@ macro_rules! tuples {
} }
} }
} }
/*
tuples!(EitherOf3 => A = 0, B = 1, C = 2); 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!(EitherOf5 => A = 0, B = 1, C = 2, D = 3, E = 4);
@ -297,3 +305,4 @@ tuples!(EitherOf13 => A = 0, B = 1, C = 2, D = 3, E = 4, F = 5, G = 6, H = 7, I
tuples!(EitherOf14 => A = 0, B = 1, C = 2, D = 3, E = 4, F = 5, G = 6, H = 7, I = 8, J = 9, K = 10, L = 11, M = 12, N = 13); tuples!(EitherOf14 => A = 0, B = 1, C = 2, D = 3, E = 4, F = 5, G = 6, H = 7, I = 8, J = 9, K = 10, L = 11, M = 12, N = 13);
tuples!(EitherOf15 => A = 0, B = 1, C = 2, D = 3, E = 4, F = 5, G = 6, H = 7, I = 8, J = 9, K = 10, L = 11, M = 12, N = 13, O = 14); tuples!(EitherOf15 => A = 0, B = 1, C = 2, D = 3, E = 4, F = 5, G = 6, H = 7, I = 8, J = 9, K = 10, L = 11, M = 12, N = 13, O = 14);
tuples!(EitherOf16 => A = 0, B = 1, C = 2, D = 3, E = 4, F = 5, G = 6, H = 7, I = 8, J = 9, K = 10, L = 11, M = 12, N = 13, O = 14, P = 15); tuples!(EitherOf16 => A = 0, B = 1, C = 2, D = 3, E = 4, F = 5, G = 6, H = 7, I = 8, J = 9, K = 10, L = 11, M = 12, N = 13, O = 14, P = 15);
*/

View File

@ -5,7 +5,7 @@ use crate::{
MatchInterface, MatchNestedRoutes, PossibleRouteMatch, RouteMatchId, MatchInterface, MatchNestedRoutes, PossibleRouteMatch, RouteMatchId,
Routes, Routes,
}, },
Params, ChooseView, Params,
}; };
use core::marker::PhantomData; use core::marker::PhantomData;
use either_of::*; use either_of::*;
@ -84,89 +84,28 @@ where
} }
} }
trait ChooseView<R> pub struct RouteData<R>
where
R: Renderer,
{
type Output;
fn choose(self, route_data: RouteData<R>) -> Self::Output;
}
pub struct RouteData<'a, R>
where where
R: Renderer, R: Renderer,
{ {
pub params: ArcMemo<Params>, pub params: ArcMemo<Params>,
pub outlet: Box<dyn FnOnce() -> AnyView<R> + 'a>, pub outlet: Box<dyn FnOnce() -> AnyView<R>>,
} }
impl<F, View, R> ChooseView<R> for F impl<Rndr, Loc, FallbackFn, Fallback, Children> Render<Rndr>
where
F: Fn(RouteData<R>) -> View,
R: Renderer,
{
type Output = View;
fn choose(self, route_data: RouteData<R>) -> Self::Output {
self(route_data)
}
}
impl<R> ChooseView<R> for ()
where
R: Renderer,
{
type Output = ();
fn choose(self, _route_data: RouteData<R>) -> Self::Output {
()
}
}
impl<A, FnA, B, FnB, Rndr> ChooseView<Rndr> for Either<FnA, FnB>
where
FnA: Fn(RouteData<Rndr>) -> A,
FnB: Fn(RouteData<Rndr>) -> B,
Rndr: Renderer,
{
type Output = Either<A, B>;
fn choose(self, route_data: RouteData<Rndr>) -> Self::Output {
match self {
Either::Left(f) => Either::Left(f(route_data)),
Either::Right(f) => Either::Right(f(route_data)),
}
}
}
impl<Rndr, Loc, FallbackFn, Fallback, Children, View> Render<Rndr>
for Router<Rndr, Loc, Children, FallbackFn> for Router<Rndr, Loc, Children, FallbackFn>
where where
Loc: Location, Loc: Location,
FallbackFn: Fn() -> Fallback + 'static, FallbackFn: Fn() -> Fallback + 'static,
Fallback: Render<Rndr>, Fallback: Render<Rndr>,
for<'a> Children: MatchNestedRoutes<'a, Rndr> + 'static, Children: MatchNestedRoutes<Rndr> + 'static,
for<'a> <<Children as MatchNestedRoutes<'a, Rndr>>::Match as MatchInterface< /*View: Render<Rndr> + IntoAny<Rndr> + 'static,
'a, View::State: 'static,*/
R,
>>::View: ChooseView<Rndr, Output = View>,
for<'a> <<Children as MatchNestedRoutes<'a, Rndr>>::Match as MatchInterface<
'a,
R,
>>::Child: std::fmt::Debug,
View: Render<Rndr> + IntoAny<Rndr> + 'static,
View::State: 'static,
Fallback::State: 'static, Fallback::State: 'static,
Rndr: Renderer + 'static, Rndr: Renderer + 'static,
{ {
type State = RenderEffect< type State =
EitherState< RenderEffect<EitherState<(), <Fallback as Render<Rndr>>::State, Rndr>>;
NestedRouteState<View::State>,
<Fallback as Render<Rndr>>::State,
Rndr,
>,
>;
type FallibleState = (); type FallibleState = ();
fn build(self) -> Self::State { fn build(self) -> Self::State {
@ -191,29 +130,33 @@ where
if let Some(new_match) = new_match { if let Some(new_match) = new_match {
match &mut prev.state { match &mut prev.state {
Either::Left(prev) => { Either::Left(prev) => {
nested_rebuild(&outer_owner, prev, new_match); //nested_rebuild(&outer_owner, prev, new_match);
} }
Either::Right(_) => { Either::Right(_) => {
Either::<_, Fallback>::Left(NestedRouteView::new( /*Either::<_, Fallback>::Left(NestedRouteView::new(
&outer_owner, &outer_owner,
new_match, new_match,
)) ))
.rebuild(&mut prev); .rebuild(&mut prev);*/
} }
} }
} else { } else {
Either::<NestedRouteView<View, Rndr>, _>::Right((self /*Either::<NestedRouteView<View, Rndr>, _>::Right((self
.fallback)( .fallback)(
)) ))
.rebuild(&mut prev); .rebuild(&mut prev);*/
} }
prev prev
} else { } else {
match new_match { match new_match {
Some(matched) => Either::Left(NestedRouteView::new( Some(matched) =>
/*Either::Left(NestedRouteView::new(
&outer_owner, &outer_owner,
matched, matched,
)), ))*/
{
Either::Left(())
}
_ => Either::Right((self.fallback)()), _ => Either::Right((self.fallback)()),
} }
.build() .build()
@ -235,14 +178,14 @@ where
} }
} }
fn nested_rebuild<'a, NewMatch, R>( /*fn nested_rebuild<NewMatch, R>(
outer_owner: &Owner, outer_owner: &Owner,
current: &mut NestedRouteState< current: &mut NestedRouteState<
<<NewMatch::View as ChooseView<R>>::Output as Render<R>>::State, <<NewMatch::View as ChooseView<R>>::Output as Render<R>>::State,
>, >,
new: NewMatch, new: NewMatch,
) where ) where
NewMatch: MatchInterface<'a, R> + 'a, NewMatch: MatchInterface<R>,
NewMatch::View: ChooseView<R>, NewMatch::View: ChooseView<R>,
<NewMatch::View as ChooseView<R>>::Output: Render<R> + IntoAny<R> + 'static, <NewMatch::View as ChooseView<R>>::Output: Render<R> + IntoAny<R> + 'static,
NewMatch::Child: std::fmt::Debug, NewMatch::Child: std::fmt::Debug,
@ -270,7 +213,7 @@ fn nested_rebuild<'a, NewMatch, R>(
// update params, in case they're different // update params, in case they're different
// TODO // TODO
} }*/
pub struct NestedRouteView<View, R> pub struct NestedRouteView<View, R>
where where
@ -288,11 +231,12 @@ impl<View, R> NestedRouteView<View, R>
where where
R: Renderer + 'static, R: Renderer + 'static,
{ {
pub fn new<'a, Matcher>(outer_owner: &Owner, route_match: Matcher) -> Self pub fn new<Matcher>(outer_owner: &Owner, route_match: Matcher) -> Self
where where
Matcher: MatchInterface<'a, R>, Matcher: for<'a> MatchInterface<'a, R, View = View> + 'static,
Matcher::View: ChooseView<R, Output = View>, for<'a> <Matcher as MatchInterface<'a, R>>::View:
Matcher::Child: std::fmt::Debug, ChooseView<R, Output = View>,
for<'a> <Matcher as MatchInterface<'a, R>>::Child: std::fmt::Debug,
View: IntoAny<R> + 'static, View: IntoAny<R> + 'static,
{ {
let params = ArcRwSignal::new( let params = ArcRwSignal::new(
@ -304,14 +248,13 @@ where
); );
let matched = ArcRwSignal::new(route_match.as_matched().to_string()); let matched = ArcRwSignal::new(route_match.as_matched().to_string());
let id = route_match.as_id(); let id = route_match.as_id();
let view = route_match.to_view(); let (view, child) = route_match.into_view_and_child();
let route_data = RouteData { let route_data = RouteData {
params: { params: {
let params = params.clone(); let params = params.clone();
ArcMemo::new(move |_| params.get()) ArcMemo::new(move |_| params.get())
}, },
outlet: Box::new({ outlet: Box::new({
let child = route_match.into_child();
move || { move || {
child child
.map(|child| { .map(|child| {
@ -323,7 +266,6 @@ where
}), }),
outlet: Box::new(|| ().into_any()) outlet: Box::new(|| ().into_any())
};*/ };*/
let view = child.to_view();
format!("{child:?}") format!("{child:?}")
}) })
.into_any() .into_any()
@ -413,11 +355,11 @@ where
} }
} }
trait RouteView<'a, R>: MatchInterface<'a, R> trait RouteView<R>: for<'a> MatchInterface<'a, R>
where where
R: Renderer, R: Renderer,
{ {
type RouteViewChild: RouteView<'a, R>; type RouteViewChild: RouteView<R>;
type RouteView: Render<R>; type RouteView: Render<R>;
fn into_child(self) -> Option<Self::RouteViewChild>; fn into_child(self) -> Option<Self::RouteViewChild>;
@ -429,14 +371,14 @@ where
Loc: Location, Loc: Location,
FallbackFn: Fn() -> Fallback + 'static, FallbackFn: Fn() -> Fallback + 'static,
Fallback: RenderHtml<Rndr>, Fallback: RenderHtml<Rndr>,
for<'a> Children: MatchNestedRoutes<'a, Rndr> + 'static, Children: MatchNestedRoutes<Rndr> + 'static,
for<'a> <<Children as MatchNestedRoutes<'a, Rndr>>::Match as MatchInterface< for<'a> <<Children as MatchNestedRoutes<Rndr>>::Match<'a> as MatchInterface<
'a, 'a,
R, Rndr,
>>::View: ChooseView<Rndr, Output = View>, >>::View: ChooseView<Rndr, Output = View>,
for<'a> <<Children as MatchNestedRoutes<'a, Rndr>>::Match as MatchInterface< for<'a> <<Children as MatchNestedRoutes<Rndr>>::Match<'a> as MatchInterface<
'a, 'a,
R, Rndr,
>>::Child: std::fmt::Debug, >>::Child: std::fmt::Debug,
View: Render<Rndr> + IntoAny<Rndr> + 'static, View: Render<Rndr> + IntoAny<Rndr> + 'static,
View::State: 'static, View::State: 'static,
@ -465,10 +407,10 @@ where
Loc: Location, Loc: Location,
FallbackFn: Fn() -> Fallback, FallbackFn: Fn() -> Fallback,
Fallback: Render<Rndr>, Fallback: Render<Rndr>,
for<'a> Children: MatchNestedRoutes<'a, Rndr>, Children: MatchNestedRoutes<Rndr>,
for<'a> <<Children as MatchNestedRoutes<'a, Rndr>>::Match as MatchInterface< for<'a> <<Children as MatchNestedRoutes<Rndr>>::Match<'a> as MatchInterface<
'a, 'a,
R, Rndr,
>>::View: ChooseView<Rndr, Output = View>, >>::View: ChooseView<Rndr, Output = View>,
Rndr: Renderer, Rndr: Renderer,
Router<Rndr, Loc, Children, FallbackFn>: RenderHtml<Rndr>, Router<Rndr, Loc, Children, FallbackFn>: RenderHtml<Rndr>,
@ -503,6 +445,7 @@ macro_rules! tuples {
where where
Rndr: Renderer, Rndr: Renderer,
$([<Fn $ty>]: Fn(RouteData<Rndr>) -> $ty,)* $([<Fn $ty>]: Fn(RouteData<Rndr>) -> $ty,)*
$($ty: Render<Rndr>,)*
{ {
type Output = $either<$($ty,)*>; type Output = $either<$($ty,)*>;