Skip to content
This repository has been archived by the owner on Jul 19, 2020. It is now read-only.

Commit

Permalink
Remove the Option wrapper from Route's state (#206)
Browse files Browse the repository at this point in the history
* Remove the option wrapper from route

* fix macros and test

* add todo
  • Loading branch information
hgzimmerman authored Dec 17, 2019
1 parent 46d70d1 commit 7837f76
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 103 deletions.
17 changes: 6 additions & 11 deletions crates/yew_router_macro/src/switch/enum_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,8 @@ pub fn generate_enum_impl(
let token_stream = quote! {
#impl_line
{
fn from_route_part<__T: ::yew_router::route::RouteState>(route: ::yew_router::route::Route<__T>) -> (::std::option::Option<Self>, ::std::option::Option<__T>) {
let mut state = route.state;
let route_string = route.route;
fn from_route_part<__T: ::yew_router::route::RouteState>(route: String, mut state: Option<__T>) -> (::std::option::Option<Self>, ::std::option::Option<__T>) {
let route_string = route;
#(#variant_matchers)*

return (::std::option::Option::None, state)
Expand Down Expand Up @@ -73,10 +72,8 @@ fn build_variant_from_captures(
let (v, s) = match captures.remove(#key) {
::std::option::Option::Some(value) => {
<#field_ty as ::yew_router::Switch>::from_route_part(
::yew_router::route::Route {
route: value,
state,
}
value,
state,
)
}
::std::option::Option::None => {
Expand Down Expand Up @@ -129,10 +126,8 @@ fn build_variant_from_captures(
let (v, s) = match drain.next() {
::std::option::Option::Some(value) => {
<#field_ty as ::yew_router::Switch>::from_route_part(
::yew_router::route::Route {
route: value,
state,
}
value,
state,
)
},
::std::option::Option::None => {
Expand Down
17 changes: 6 additions & 11 deletions crates/yew_router_macro/src/switch/struct_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@ pub fn generate_struct_impl(item: SwitchItem, generics: Generics) -> TokenStream
let token_stream = quote! {
#impl_line
{
fn from_route_part<__T: ::yew_router::route::RouteState>(route: ::yew_router::route::Route<__T>) -> (::std::option::Option<Self>, ::std::option::Option<__T>) {
fn from_route_part<__T: ::yew_router::route::RouteState>(route: String, mut state: Option<__T>) -> (::std::option::Option<Self>, ::std::option::Option<__T>) {

#matcher
let mut state = route.state;
let route_string = route.route;
let route_string = route;

#build_from_captures

Expand Down Expand Up @@ -62,10 +61,8 @@ fn build_struct_from_captures(ident: &Ident, fields: &Fields) -> TokenStream2 {
let (v, s) = match captures.remove(#key) {
::std::option::Option::Some(value) => {
<#field_ty as ::yew_router::Switch>::from_route_part(
::yew_router::route::Route {
route: value,
state,
}
value,
state,
)
}
::std::option::Option::None => {
Expand Down Expand Up @@ -108,10 +105,8 @@ fn build_struct_from_captures(ident: &Ident, fields: &Fields) -> TokenStream2 {
let (v, s) = match drain.next() {
::std::option::Option::Some(value) => {
<#field_ty as ::yew_router::Switch>::from_route_part(
::yew_router::route::Route {
route: value,
state,
}
value,
state,
)
},
::std::option::Option::None => {
Expand Down
11 changes: 3 additions & 8 deletions examples/minimal/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,7 @@ impl Component for Model {
let mut route_service: RouteService<()> = RouteService::new();
let route = route_service.get_route();
let route = Route::from(route);
let callback = link.callback(|(route, state)| -> Msg {
Msg::RouteChanged(Route {
route,
state: Some(state),
})
});
let callback = link.callback(Msg::RouteChanged);
route_service.register_callback(callback);

Model {
Expand All @@ -78,9 +73,9 @@ impl Component for Model {
AppRoute::C => format!("/c"),
};
self.route_service.set_route(&route_string, ());
self.route = Route {
self.route = Route{
route: route_string,
state: None,
state: (),
};
}
}
Expand Down
22 changes: 10 additions & 12 deletions src/agent/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub use dispatcher::RouteAgentDispatcher;
#[derive(Debug)]
pub enum Msg<T> {
/// Message for when the route is changed.
BrowserNavigationRouteChanged((String, T)),
BrowserNavigationRouteChanged(Route<T>), // TODO make this a route?
}

/// Input message type for interacting with the `RouteAgent'.
Expand Down Expand Up @@ -105,10 +105,8 @@ where

fn update(&mut self, msg: Self::Message) {
match msg {
Msg::BrowserNavigationRouteChanged((_route_string, state)) => {
Msg::BrowserNavigationRouteChanged(route) => {
trace!("Browser navigated");
let mut route = Route::current_route(&self.route_service);
route.state = Some(state);
for sub in &self.subscribers {
self.link.respond(*sub, route.clone());
}
Expand All @@ -125,24 +123,24 @@ where
RouteRequest::ReplaceRoute(route) => {
let route_string: String = route.to_string();
self.route_service
.replace_route(&route_string, route.state.unwrap_or_default());
let route = Route::current_route(&self.route_service);
.replace_route(&route_string, route.state);
let route = self.route_service.get_route();
for sub in &self.subscribers {
self.link.respond(*sub, route.clone());
}
}
RouteRequest::ReplaceRouteNoBroadcast(route) => {
let route_string: String = route.to_string();
self.route_service
.replace_route(&route_string, route.state.unwrap_or_default());
.replace_route(&route_string, route.state);
}
RouteRequest::ChangeRoute(route) => {
let route_string: String = route.to_string();
// set the route
self.route_service
.set_route(&route_string, route.state.unwrap_or_default());
// get the new route. This will contain a default state object
let route = Route::current_route(&self.route_service);
.set_route(&route_string, route.state);
// get the new route.
let route = self.route_service.get_route();
// broadcast it to all listening components
for sub in &self.subscribers {
self.link.respond(*sub, route.clone());
Expand All @@ -151,10 +149,10 @@ where
RouteRequest::ChangeRouteNoBroadcast(route) => {
let route_string: String = route.to_string();
self.route_service
.set_route(&route_string, route.state.unwrap_or_default());
.set_route(&route_string, route.state);
}
RouteRequest::GetCurrentRoute => {
let route = Route::current_route(&self.route_service);
let route = self.route_service.get_route();
self.link.respond(who, route.clone());
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ pub use self::{router_button::RouterButton, router_link::RouterAnchor, router_li
use crate::RouterState;

// TODO This should also be PartialEq and Clone. Its blocked on Children not supporting that.
// TODO This should no longer take link & String, and instead take a route: T implementing Switch
/// Properties for `RouterButton` and `RouterLink`.
#[derive(Properties, Default, Debug)]
pub struct Props<T: RouterState> {
/// The route that will be set when the component is clicked.
pub link: String,
/// The state to set when changing the route.
pub state: Option<T>,
pub state: T,
#[deprecated(note = "Use children field instead (nested html)")]
/// The text to display.
pub text: String,
Expand Down
24 changes: 4 additions & 20 deletions src/route.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//! Wrapper around route url string, and associated history state.
use crate::service::RouteService;
use serde::{Deserialize, Serialize};
use std::{fmt, ops::Deref};
use stdweb::{unstable::TryFrom, Value};
Expand All @@ -16,7 +15,7 @@ pub struct Route<T = ()> {
/// The route string
pub route: String,
/// The state stored in the history api
pub state: Option<T>,
pub state: T,
}

/// Formats a path, query, and fragment into a string.
Expand All @@ -32,33 +31,18 @@ pub(crate) fn format_route_string(path: &str, query: &str, fragment: &str) -> St
)
}

impl<T> Route<T> {
/// Gets the current route from the route service.
///
/// # Note
/// It does not get the current state.
/// That is only provided via events.
/// See [RouteService.register_callback](struct.RouteService.html#method.register_callback) to
/// acquire state.
pub fn current_route(route_service: &RouteService<T>) -> Self {
let route = route_service.get_route();
// TODO, should try to get the state using the history api once that is exposed through
// stdweb. https://github.com/koute/stdweb/issues/371
Route { route, state: None }
}
}

impl<T> fmt::Display for Route<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
std::fmt::Display::fmt(&self.route, f)
}
}

impl<T> From<&str> for Route<T> {
// This is getting removed anyway
impl<T: Default> From<&str> for Route<T> {
fn from(string: &str) -> Route<T> {
Route {
route: string.to_string(),
state: None,
state: T::default(),
}
}
}
Expand Down
54 changes: 43 additions & 11 deletions src/service.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
//! Service that interfaces with the browser to handle routing.
use stdweb::{
web::{event::PopStateEvent, window, EventListenerHandle, History, IEventTarget, Location},
Value,
};
use stdweb::{web::{event::PopStateEvent, window, EventListenerHandle, History, IEventTarget, Location}, Value};
use yew::callback::Callback;

use crate::route::RouteState;
use crate::route::{RouteState, Route};
use std::marker::PhantomData;
use stdweb::unstable::TryFrom;
use stdweb::unstable::TryInto;
use stdweb::js;

/// A service that facilitates manipulation of the browser's URL bar and responding to browser events
/// when users press 'forward' or 'back'.
Expand Down Expand Up @@ -53,10 +52,7 @@ impl<T> RouteService<T> {
crate::route::format_route_string(&path, &query, &fragment)
}

/// Gets the concatenated path, query, and fragment.
pub fn get_route(&self) -> String {
Self::get_route_from_location(&self.location)
}


/// Gets the path name of the current url.
pub fn get_path(&self) -> String {
Expand All @@ -81,7 +77,7 @@ where
/// Registers a callback to the route service.
/// Callbacks will be called when the History API experiences a change such as
/// popping a state off of its stack when the forward or back buttons are pressed.
pub fn register_callback(&mut self, callback: Callback<(String, T)>) {
pub fn register_callback(&mut self, callback: Callback<Route<T>>) {
self.event_listener = Some(window().add_event_listener(move |event: PopStateEvent| {
let state_value: Value = event.state();
let state_string: String = String::try_from(state_value).unwrap_or_default();
Expand All @@ -96,7 +92,8 @@ where
let location: Location = window().location().unwrap();
let route: String = Self::get_route_from_location(&location);

callback.emit((route.clone(), state))

callback.emit(Route{route, state})
}));
}

Expand All @@ -121,4 +118,39 @@ where
});
let _ = self.history.replace_state(state_string, "", Some(route));
}

/// Gets the concatenated path, query, and fragment.
pub fn get_route(&self) -> Route<T> {
let route_string = Self::get_route_from_location(&self.location);
let state: T = get_state_string(&self.history)
.or_else(|| {
log::trace!("History state is empty");
None
})
.and_then(|state_string| -> Option<Option<T>>{
serde_json::from_str(&state_string)
.ok()
.or_else(|| {
log::error!("Could not deserialize state string");
None
})
})
.and_then(std::convert::identity) // flatten
.unwrap_or_default();
Route {
route: route_string,
state
}
}
}

fn get_state(history: &History) -> Value {
js!(
return @{history}.state;
)
}

fn get_state_string(history: &History) -> Option<String> {
get_state(history).try_into().ok()
}

Loading

0 comments on commit 7837f76

Please sign in to comment.