freya_router/
navigation.rs1use std::{
4 fmt::{
5 Debug,
6 Display,
7 },
8 str::FromStr,
9};
10
11use url::{
12 ParseError,
13 Url,
14};
15
16use crate::{
17 components::child_router::consume_child_route_mapping,
18 prelude::RouterContext,
19 routable::Routable,
20};
21
22impl<R: Routable> From<R> for NavigationTarget {
23 fn from(value: R) -> Self {
24 let mapping = consume_child_route_mapping();
26 match mapping.as_ref() {
27 Some(mapping) => NavigationTarget::Internal(mapping.format_route_as_root_route(value)),
28 None => NavigationTarget::Internal(value.to_string()),
30 }
31 }
32}
33
34#[derive(Clone, PartialEq, Eq, Debug)]
36pub enum NavigationTarget<R = String> {
37 Internal(R),
59 External(String),
61}
62
63impl<R: Routable> From<&str> for NavigationTarget<R> {
64 fn from(value: &str) -> Self {
65 value
66 .parse()
67 .unwrap_or_else(|_| Self::External(value.to_string()))
68 }
69}
70
71impl<R: Routable> From<&String> for NavigationTarget<R> {
72 fn from(value: &String) -> Self {
73 value.as_str().into()
74 }
75}
76
77impl<R: Routable> From<String> for NavigationTarget<R> {
78 fn from(value: String) -> Self {
79 value.as_str().into()
80 }
81}
82
83impl<R: Routable> From<R> for NavigationTarget<R> {
84 fn from(value: R) -> Self {
85 Self::Internal(value)
86 }
87}
88
89impl From<&str> for NavigationTarget {
90 fn from(value: &str) -> Self {
91 match RouterContext::try_get() {
92 Some(router) => match router.internal_route(value) {
93 true => NavigationTarget::Internal(value.to_string()),
94 false => NavigationTarget::External(value.to_string()),
95 },
96 None => NavigationTarget::External(value.to_string()),
97 }
98 }
99}
100
101impl From<String> for NavigationTarget {
102 fn from(value: String) -> Self {
103 match RouterContext::try_get() {
104 Some(router) => match router.internal_route(&value) {
105 true => NavigationTarget::Internal(value),
106 false => NavigationTarget::External(value),
107 },
108 None => NavigationTarget::External(value.to_string()),
109 }
110 }
111}
112
113impl<R: Routable> From<NavigationTarget<R>> for NavigationTarget {
114 fn from(value: NavigationTarget<R>) -> Self {
115 match value {
116 NavigationTarget::Internal(r) => r.into(),
117 NavigationTarget::External(s) => Self::External(s),
118 }
119 }
120}
121
122impl<R: Routable> Display for NavigationTarget<R> {
123 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124 match self {
125 NavigationTarget::Internal(r) => write!(f, "{r}"),
126 NavigationTarget::External(s) => write!(f, "{s}"),
127 }
128 }
129}
130
131pub enum NavigationTargetParseError<R: Routable> {
133 InvalidUrl(ParseError),
135 InvalidInternalURL(<R as FromStr>::Err),
137}
138
139impl<R: Routable> Debug for NavigationTargetParseError<R> {
140 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141 match self {
142 NavigationTargetParseError::InvalidUrl(e) => write!(f, "Invalid URL: {e}"),
143 NavigationTargetParseError::InvalidInternalURL(_) => {
144 write!(f, "Invalid internal URL")
145 }
146 }
147 }
148}
149
150impl<R: Routable> FromStr for NavigationTarget<R> {
151 type Err = NavigationTargetParseError<R>;
152
153 fn from_str(s: &str) -> Result<Self, Self::Err> {
154 match Url::parse(s) {
155 Ok(_) => Ok(Self::External(s.to_string())),
156 Err(ParseError::RelativeUrlWithoutBase) => {
157 Ok(Self::Internal(R::from_str(s).map_err(|e| {
158 NavigationTargetParseError::InvalidInternalURL(e)
159 })?))
160 }
161 Err(e) => Err(NavigationTargetParseError::InvalidUrl(e)),
162 }
163 }
164}