use crate::history::HistoryProvider; use dioxus::prelude::*; use std::str::FromStr; #[derive(Debug, PartialEq)] pub struct RouteParseError { pub attempted_routes: Vec, } impl std::fmt::Display for RouteParseError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Route did not match:\nAttempted Matches:\n")?; for (i, route) in self.attempted_routes.iter().enumerate() { writeln!(f, "{}) {route}", i + 1)?; } Ok(()) } } struct Router where ::Err: std::fmt::Display, { history: H, route: R, } impl Router where ::Err: std::fmt::Display, { fn new(history: H) -> Result { let path = history.current_path(); Ok(Self { history, route: R::from_str(path.as_str())?, }) } } pub trait FromQuery { fn from_query(query: &str) -> Self; } impl From<&'a str>> FromQuery for T { fn from_query(query: &str) -> Self { T::from(query) } } pub trait FromRouteSegment: Sized { type Err; fn from_route_segment(route: &str) -> Result; } impl FromRouteSegment for T where ::Err: std::fmt::Display, { type Err = ::Err; fn from_route_segment(route: &str) -> Result { T::from_str(route) } } pub trait ToRouteSegments { fn display_route_segements(self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result; } impl ToRouteSegments for I where I: IntoIterator, { fn display_route_segements(self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for segment in self { write!(f, "/")?; write!(f, "{}", segment)?; } Ok(()) } } pub trait FromRouteSegments: Sized { type Err; fn from_route_segments(segments: &[&str]) -> Result; } impl> FromRouteSegments for I { type Err = ::Err; fn from_route_segments(segments: &[&str]) -> Result { segments .iter() .map(|s| String::from_route_segment(s)) .collect() } } #[derive(Props, PartialEq)] pub struct RouterProps { pub current_route: String, } pub trait Routable: FromStr + std::fmt::Display + Clone where ::Err: std::fmt::Display, { fn render(self, cx: &ScopeState) -> Element; fn comp(cx: Scope) -> Element where Self: 'static, { let router = Self::from_str(&cx.props.current_route); match router { Ok(router) => router.render(cx), Err(err) => { render! { pre { "{err}" } } } } } }