Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement TryFromSegments for impl Route for nested routes #281

Merged
merged 1 commit into from
Oct 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 33 additions & 8 deletions docs/next/advanced/routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ example which are both static.

Static routes can also be nested, e.g. `"/my/nested/path"`.

#### Dynamic parameters
### Dynamic parameters

Path parameters can be dynamic by using angle brackets around a variable name in the route's path.
This will allow any segment to match the route in that position.
Expand Down Expand Up @@ -121,10 +121,11 @@ be completed. For example, the following route will **not** capture the final `e
#[to("/start/<path..>/<end>")]
Path {
path: Vec<String>,
end: String,
}
```

#### Unit variants
### Unit variants

Enum unit variants are also supported. The following route has the same behavior as the hello
example from before.
Expand All @@ -134,17 +135,17 @@ example from before.
Hello(String)
```

#### Capture types
### Capture types

Capture variables are not limited to `String`. In fact, any type that implements the
[`FromParam`](https://docs.rs/sycamore-router/latest/sycamore_router/trait.FromParam.html) trait can
be used as a capture.
[`TryFromParam`](https://docs.rs/sycamore-router/latest/sycamore_router/trait.TryFromParam.html)
trait can be used as a capture.

This trait is automatically implemented for types that already implement `FromStr`, which includes
many standard library types.

Because `FromParam` is fallible, the route will only match if the parameter can be parsed into the
corresponding type.
Because `TryFromParam` is fallible, the route will only match if the parameter can be parsed into
the corresponding type.

For example, `/account/123` will match the following route but `/account/abc` will not.

Expand All @@ -154,9 +155,33 @@ Account { id: u32 }
```

Likewise, the
[`FromSegments`](https://docs.rs/sycamore-router/latest/sycamore_router/trait.FromSegments.html)
[`TryFromSegments`](https://docs.rs/sycamore-router/latest/sycamore_router/trait.TryFromSegments.html)
trait is the equivalent for dynamic segments.

### Nested routes

Routes can also be nested! The following code will route any url to `/route/..` to `Nested`.

```rust
#[derive(Route)]
enum Nested {
#[to("/nested")]
Nested,
#[not_found]
NotFound,
}

#[derive(Route)]
enum Routes {
#[to("/")]
Home,
#[to("/route/<_..>")]
Route(Nested),
#[not_found]
NotFound,
}
```

## Using `Router`

To display content based on the route that matches, we can use a `Router`.
Expand Down
38 changes: 38 additions & 0 deletions packages/sycamore-router/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,12 @@ where
}
}

impl<T: Route> TryFromSegments for T {
fn try_from_segments(segments: &[&str]) -> Option<Self> {
Some(T::match_route(segments))
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -474,5 +480,37 @@ mod tests {
}
);
}

#[test]
fn nested_router() {
#[derive(Debug, PartialEq, Eq, Route)]
enum Nested {
#[to("/nested")]
Nested,
#[not_found]
NotFound,
}

#[derive(Debug, PartialEq, Eq, Route)]
enum Routes {
#[to("/")]
Home,
#[to("/route/<_..>")]
Route(Nested),
#[not_found]
NotFound,
}

assert_eq!(Routes::match_route(&[]), Routes::Home);
assert_eq!(
Routes::match_route(&["route", "nested"]),
Routes::Route(Nested::Nested)
);
assert_eq!(
Routes::match_route(&["route", "404"]),
Routes::Route(Nested::NotFound)
);
assert_eq!(Routes::match_route(&["404"]), Routes::NotFound);
}
}
}