From 0deb2e15cbbe844959929ec4ae0d4f11008c33d5 Mon Sep 17 00:00:00 2001 From: Henry Zimmerman Date: Tue, 17 Dec 2019 16:19:59 -0500 Subject: [PATCH] Add a feature gate for service (#204) * Add a feature gate for service * fix minimal readme * remove yew as a dependency when compiling with no features * add todo to remove unit_state * implement Switch generically * fix permissive in router_component example * fix tests * add method for creating a route with its default state * other merged * cleanup dead code, move formatting route code to service --- Cargo.toml | 18 +-- .../yew_router_macro/src/switch/enum_impl.rs | 2 +- .../src/switch/struct_impl.rs | 2 +- examples/minimal/Cargo.toml | 2 +- examples/minimal/README.md | 4 +- examples/router_component/src/main.rs | 10 +- examples/switch/Cargo.toml | 2 +- examples/switch/src/main.rs | 25 ++-- src/lib.rs | 20 +++- src/route.rs | 47 ++++---- src/service.rs | 17 ++- src/switch.rs | 108 +++++++----------- tests/macro_test/src/lib.rs | 73 ++++++------ 13 files changed, 168 insertions(+), 162 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 45e1865..b670131 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,21 +14,23 @@ repository = "https://github.com/yewstack/yew_router" [features] default = ["core", "unit_alias"] -core = ["router", "components"] +core = ["router", "components"] # Most everything + +# TODO remove this unit_alias = [] -router = ["agent"] -components = ["agent" ] -agent = [] +router = ["agent"] # The Router component +components = ["agent" ] # The button and anchor +agent = ["service"] # The RouteAgent +service = ["stdweb", "yew"] # The RouteService [dependencies] log = "0.4.8" -serde = "1.0.103" -serde_derive = "1.0.103" +serde = {version = "1.0.103", features = ["derive"]} #yew = "0.10.0" -yew = {git = "https://github.com/yewstack/yew", branch = "master"} -stdweb = "0.4.20" +yew = {git = "https://github.com/yewstack/yew", branch = "master", optional = true} +stdweb = {version = "0.4.20", optional = true} yew-router-route-parser = {path = "crates/yew_router_route_parser", version = "0.8.0"} yew-router-macro = {path = "crates/yew_router_macro", version = "0.8.0"} diff --git a/crates/yew_router_macro/src/switch/enum_impl.rs b/crates/yew_router_macro/src/switch/enum_impl.rs index a417b3f..59b3613 100644 --- a/crates/yew_router_macro/src/switch/enum_impl.rs +++ b/crates/yew_router_macro/src/switch/enum_impl.rs @@ -33,7 +33,7 @@ pub fn generate_enum_impl( let token_stream = quote! { #impl_line { - fn from_route_part<__T: ::yew_router::route::RouteState>(route: String, mut state: Option<__T>) -> (::std::option::Option, ::std::option::Option<__T>) { + fn from_route_part<__T>(route: String, mut state: Option<__T>) -> (::std::option::Option, ::std::option::Option<__T>) { let route_string = route; #(#variant_matchers)* diff --git a/crates/yew_router_macro/src/switch/struct_impl.rs b/crates/yew_router_macro/src/switch/struct_impl.rs index 9dbcf28..024743c 100644 --- a/crates/yew_router_macro/src/switch/struct_impl.rs +++ b/crates/yew_router_macro/src/switch/struct_impl.rs @@ -24,7 +24,7 @@ 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: String, mut state: Option<__T>) -> (::std::option::Option, ::std::option::Option<__T>) { + fn from_route_part<__T>(route: String, mut state: Option<__T>) -> (::std::option::Option, ::std::option::Option<__T>) { #matcher let route_string = route; diff --git a/examples/minimal/Cargo.toml b/examples/minimal/Cargo.toml index d6ccf9f..9202fb9 100644 --- a/examples/minimal/Cargo.toml +++ b/examples/minimal/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" [dependencies] #yew = "0.10.0" yew = {git = "https://github.com/yewstack/yew", branch = "master"} -yew-router = {path = "../../", default-features=false} +yew-router = {path = "../../", default-features=false, features = ["service"]} web_logger = "0.1" log = "0.4.8" wee_alloc = "0.4.5" diff --git a/examples/minimal/README.md b/examples/minimal/README.md index 85c4aec..4ff2bef 100644 --- a/examples/minimal/README.md +++ b/examples/minimal/README.md @@ -1,7 +1,7 @@ # Minimal Example -This example shows how to use this library without any of the features turned on. -Without any features, you lack the `Router` component and `RouteAgent` and its associated bridges and dispatchers. +This example shows how to use this library with only the "service" feature turned on. +Without most of the features, you lack the `Router` component and `RouteAgent` and its associated bridges and dispatchers. This means that you must use the `RouteService` to interface with the browser to handle route changes. Removing the `Router` component means that you have to deal with the `RouteService` directly and propagate change route messages up to the component that contains the `RouteService`. diff --git a/examples/router_component/src/main.rs b/examples/router_component/src/main.rs index 7968c5b..9ba4d69 100644 --- a/examples/router_component/src/main.rs +++ b/examples/router_component/src/main.rs @@ -13,7 +13,7 @@ use crate::{ c_component::CModel, }; use yew::virtual_dom::VNode; -use yew_router::switch::AllowMissing; +use yew_router::switch::{AllowMissing, Permissive}; #[global_allocator] static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; @@ -62,12 +62,12 @@ impl Component for Model { }, AppRoute::C => html!{}, AppRoute::E(string) => html!{format!("hello {}", string)}, - AppRoute::PageNotFound(None) => html!{"Page not found"}, - AppRoute::PageNotFound(Some(missed_route)) => html!{format!("Page '{}' not found", missed_route)} + AppRoute::PageNotFound(Permissive(None)) => html!{"Page not found"}, + AppRoute::PageNotFound(Permissive(Some(missed_route))) => html!{format!("Page '{}' not found", missed_route)} } }) redirect = Router::redirect(|route: Route| { - AppRoute::PageNotFound(Some(route.route)) + AppRoute::PageNotFound(Permissive(Some(route.route))) }) /> @@ -87,7 +87,7 @@ pub enum AppRoute { #[to = "/e/{string}"] E(String), #[to = "/page-not-found"] - PageNotFound(Option), + PageNotFound(Permissive), } #[derive(Debug, Switch, PartialEq, Clone, Copy)] diff --git a/examples/switch/Cargo.toml b/examples/switch/Cargo.toml index 4aa31ca..3612895 100644 --- a/examples/switch/Cargo.toml +++ b/examples/switch/Cargo.toml @@ -7,4 +7,4 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -yew-router = {path = "../../"} +yew-router = {path = "../../", default-features=false} diff --git a/examples/switch/src/main.rs b/examples/switch/src/main.rs index 7e4223f..04607ca 100644 --- a/examples/switch/src/main.rs +++ b/examples/switch/src/main.rs @@ -1,35 +1,36 @@ use yew_router::{route::Route, Switch}; +use yew_router::switch::Permissive; fn main() { - let route = Route::<()>::from("/some/route"); + let route = Route::new_no_state("/some/route"); let app_route = AppRoute::switch(route); dbg!(app_route); - let route = Route::<()>::from("/some/thing/other"); + let route = Route::new_no_state("/some/thing/other"); let app_route = AppRoute::switch(route); dbg!(app_route); - let route = Route::<()>::from("/another/other"); + let route = Route::new_no_state("/another/other"); let app_route = AppRoute::switch(route); dbg!(app_route); - let route = Route::<()>::from("/inner/left"); + let route = Route::new_no_state("/inner/left"); let app_route = AppRoute::switch(route); dbg!(app_route); - let route = Route::<()>::from("/yeet"); // should not match + let route = Route::new_no_state("/yeet"); // should not match let app_route = AppRoute::switch(route); dbg!(app_route); - let route = Route::<()>::from("/single/32"); + let route = Route::new_no_state("/single/32"); let app_route = AppRoute::switch(route); dbg!(app_route); - let route = Route::<()>::from("/othersingle/472"); + let route = Route::new_no_state("/othersingle/472"); let app_route = AppRoute::switch(route); dbg!(app_route); - let route = Route::<()>::from("/option/test"); + let route = Route::new_no_state("/option/test"); let app_route = AppRoute::switch(route); dbg!(app_route); @@ -69,12 +70,12 @@ pub enum AppRoute { Single(Single), #[rest] OtherSingle(OtherSingle), - /// Because this is an option, the inner item doesn't have to match. + /// Because this is permissive, the inner item doesn't have to match. #[to = "/option/{}"] - Optional(Option), - /// Because this is an option, a corresponding capture group doesn't need to exist + Optional(Permissive), + /// Because this is permissive, a corresponding capture group doesn't need to exist #[to = "/missing/capture"] - MissingCapture(Option), + MissingCapture(Permissive), } #[derive(Switch, Debug, Clone)] diff --git a/src/lib.rs b/src/lib.rs index 092fd31..9eb71d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,6 +59,8 @@ pub use yew_router_route_parser; #[macro_use] mod alias; + +#[cfg(feature = "service")] pub mod service; #[cfg(feature = "agent")] @@ -72,6 +74,7 @@ pub mod components; #[cfg(feature = "router")] pub mod router; +/// TODO remove this /// Contains aliases and functions for working with this library using a state of type `()`. #[cfg(feature = "unit_alias")] pub mod unit_state { @@ -83,26 +86,32 @@ pub mod unit_state { pub mod prelude { pub use super::matcher::Captures; + #[cfg(feature = "service")] + pub use crate::service::RouteService; + #[cfg(feature = "service")] + pub use crate::route::RouteState; + #[cfg(feature = "agent")] pub use crate::agent::RouteAgent; #[cfg(feature = "agent")] pub use crate::agent::RouteAgentBridge; #[cfg(feature = "agent")] pub use crate::agent::RouteAgentDispatcher; + #[cfg(feature = "components")] pub use crate::components::RouterAnchor; #[cfg(feature = "components")] pub use crate::components::RouterButton; + #[cfg(feature = "router")] pub use crate::router::Router; - pub use crate::{route::Route, service::RouteService}; - pub use crate::switch::{Switch, Routable}; - pub use yew_router_macro::Switch; - // State restrictions - pub use crate::route::RouteState; #[cfg(feature = "router")] pub use crate::router::RouterState; + + pub use crate::route::Route; + pub use crate::switch::{Switch, Routable}; + pub use yew_router_macro::Switch; } pub use alias::*; @@ -111,6 +120,7 @@ pub mod matcher; pub use matcher::Captures; +#[cfg(feature = "service")] pub use crate::route::RouteState; #[cfg(feature = "router")] pub use crate::router::RouterState; diff --git a/src/route.rs b/src/route.rs index 57a594c..b80affc 100644 --- a/src/route.rs +++ b/src/route.rs @@ -1,12 +1,17 @@ //! Wrapper around route url string, and associated history state. +#[cfg(feature = "service")] +use stdweb::{unstable::TryFrom, Value}; +#[cfg(feature = "service")] +use serde::de::DeserializeOwned; + use serde::{Deserialize, Serialize}; use std::{fmt, ops::Deref}; -use stdweb::{unstable::TryFrom, Value}; use std::fmt::Debug; -use serde::de::DeserializeOwned; /// Any state that can be used in the router agent must meet the criteria of this trait. +#[cfg(feature = "service")] pub trait RouteState: Serialize + DeserializeOwned + Debug + Clone + Default + TryFrom + 'static {} +#[cfg(feature = "service")] impl RouteState for T where T: Serialize + DeserializeOwned + Debug + Clone + Default + TryFrom + 'static {} /// The representation of a route, segmented into different sections for easy access. @@ -18,35 +23,35 @@ pub struct Route { pub state: T, } -/// Formats a path, query, and fragment into a string. -/// -/// # Note -/// This expects that all three already have their expected separators (?, #, etc) -pub(crate) fn format_route_string(path: &str, query: &str, fragment: &str) -> String { - format!( - "{path}{query}{fragment}", - path = path, - query = query, - fragment = fragment - ) -} -impl fmt::Display for Route { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - std::fmt::Display::fmt(&self.route, f) +impl Route<()> { + /// Creates a new route with no state out of a string. + /// + /// This Route will have `()` for its state. + pub fn new_no_state>(route: T) -> Self { + Route { + route: route.as_ref().to_string(), + state: (), + } } } -// This is getting removed anyway -impl From<&str> for Route { - fn from(string: &str) -> Route { +impl Route { + /// Creates a new route out of a string, setting the state to its default value. + pub fn new_default_state>(route: U) -> Self { Route { - route: string.to_string(), + route: route.as_ref().to_string(), state: T::default(), } } } +impl fmt::Display for Route { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + std::fmt::Display::fmt(&self.route, f) + } +} + impl Deref for Route { type Target = String; diff --git a/src/service.rs b/src/service.rs index 77f4751..f80ae9b 100644 --- a/src/service.rs +++ b/src/service.rs @@ -49,7 +49,7 @@ impl RouteService { let path = location.pathname().unwrap(); let query = location.search().unwrap(); let fragment = location.hash().unwrap(); - crate::route::format_route_string(&path, &query, &fragment) + format_route_string(&path, &query, &fragment) } @@ -144,6 +144,21 @@ where } } + +/// Formats a path, query, and fragment into a string. +/// +/// # Note +/// This expects that all three already have their expected separators (?, #, etc) +pub(crate) fn format_route_string(path: &str, query: &str, fragment: &str) -> String { + format!( + "{path}{query}{fragment}", + path = path, + query = query, + fragment = fragment + ) +} + + fn get_state(history: &History) -> Value { js!( return @{history}.state; diff --git a/src/switch.rs b/src/switch.rs index 8ea456f..736a649 100644 --- a/src/switch.rs +++ b/src/switch.rs @@ -1,5 +1,5 @@ //! Parses routes into enums or structs. -use crate::{route::Route, RouteState}; +use crate::{route::Route}; use std::fmt::Write; /// Alias to Switch. @@ -29,32 +29,32 @@ pub type Routable = Switch; /// } /// /// assert_eq!( -/// TestEnum::switch(Route::<()>::from("/test/route")), +/// TestEnum::switch(Route::new_no_state("/test/route")), /// Some(TestEnum::TestRoute) /// ); /// assert_eq!( -/// TestEnum::switch(Route::<()>::from("/capture/string/lorem")), +/// TestEnum::switch(Route::new_no_state("/capture/string/lorem")), /// Some(TestEnum::CaptureString { /// path: "lorem".to_string() /// }) /// ); /// assert_eq!( -/// TestEnum::switch(Route::<()>::from("/capture/number/22")), +/// TestEnum::switch(Route::new_no_state("/capture/number/22")), /// Some(TestEnum::CaptureNumber { num: 22 }) /// ); /// assert_eq!( -/// TestEnum::switch(Route::<()>::from("/capture/unnamed/lorem")), +/// TestEnum::switch(Route::new_no_state("/capture/unnamed/lorem")), /// Some(TestEnum::CaptureUnnamed("lorem".to_string())) /// ); /// ``` pub trait Switch: Sized { /// Based on a route, possibly produce an itself. - fn switch(route: Route) -> Option { + fn switch(route: Route) -> Option { Self::from_route_part(route.route, Some(route.state)).0 } /// Get self from a part of the state - fn from_route_part(part: String, state: Option) -> (Option, Option); + fn from_route_part(part: String, state: Option) -> (Option, Option); /// Build part of a route from itself. fn build_route_section(self, route: &mut String) -> Option; @@ -81,7 +81,7 @@ pub trait Switch: Sized { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct LeadingSlash(pub T); impl Switch for LeadingSlash { - fn from_route_part(part: String, state: Option) -> (Option, Option) { + fn from_route_part(part: String, state: Option) -> (Option, Option) { if part.starts_with('/') { let part = part[1..].to_string(); let (inner, state) = U::from_route_part(part, state); @@ -97,20 +97,24 @@ impl Switch for LeadingSlash { } } -impl Switch for Option { +/// Successfully match even when the captured section can't be found. +#[derive(Debug, PartialEq, Clone, Copy)] +pub struct Permissive(pub Option); + +impl Switch for Permissive { /// Option is very permissive in what is allowed. - fn from_route_part(part: String, state: Option) -> (Option, Option) { + fn from_route_part(part: String, state: Option) -> (Option, Option) { let (inner, inner_state) = U::from_route_part(part, state); if inner.is_some() { - (Some(inner), inner_state) + (Some(Permissive(inner)), inner_state) } else { // The Some(None) here indicates that this will produce a None, if the wrapped value can't be parsed - (Some(None), None) + (Some(Permissive(None)), None) } } fn build_route_section(self, route: &mut String) -> Option { - if let Some(inner) = self { + if let Some(inner) = self.0 { inner.build_route_section(route) } else { None @@ -118,16 +122,19 @@ impl Switch for Option { } fn key_not_available() -> Option { - Some(None) + Some(Permissive(None)) } } +// TODO the AllowMissing shim doesn't appear to offer much over Permissive. +// Documentation should improve (need examples - to show the difference) or it should be removed. + /// Allows a section to match, providing a None value, /// if its contents are entirely missing, or starts with a '/'. #[derive(Debug, PartialEq, Clone, Copy)] -pub struct AllowMissing(pub Option); +pub struct AllowMissing(pub Option); impl Switch for AllowMissing { - fn from_route_part(part: String, state: Option) -> (Option, Option) { + fn from_route_part(part: String, state: Option) -> (Option, Option) { let route = part.clone(); let (inner, inner_state) = U::from_route_part(part, state); @@ -154,56 +161,6 @@ impl Switch for AllowMissing { } } -macro_rules! impl_switch_for_from_to_str { - ($($SelfT: ty),*) => { - $( - impl Switch for $SelfT { - fn from_route_part(part: String, state: Option) -> (Option, Option) { - ( - ::std::str::FromStr::from_str(&part).ok(), - state - ) - } - - fn build_route_section(self, f: &mut String) -> Option { - write!(f, "{}", self).expect("Writing to string should never fail."); - None - } - } - )* - }; -} - -impl_switch_for_from_to_str! { - String, - uuid::Uuid, - bool, - f64, - f32, - usize, - u128, - u64, - u32, - u16, - u8, - isize, - i128, - i64, - i32, - i16, - i8, - std::num::NonZeroU128, - std::num::NonZeroU64, - std::num::NonZeroU32, - std::num::NonZeroU16, - std::num::NonZeroU8, - std::num::NonZeroI128, - std::num::NonZeroI64, - std::num::NonZeroI32, - std::num::NonZeroI16, - std::num::NonZeroI8 -} - /// Builds a route from a switch. fn build_route_from_switch(switch: T) -> Route { // URLs are recommended to not be over 255 characters, @@ -223,6 +180,21 @@ impl From for Route { } } + +impl Switch for T { + fn from_route_part(part: String, state: Option) -> (Option, Option) { + ( + ::std::str::FromStr::from_str(&part).ok(), + state + ) + } + + fn build_route_section(self, route: &mut String) -> Option { + write!(route, "{}", self).expect("Writing to string should never fail."); + None + } +} + #[cfg(test)] mod test { use super::*; @@ -263,10 +235,10 @@ mod test { #[test] fn can_get_option_string_from_empty_str() { - let (s, _state): (Option>, Option<()>) = Option::from_route_part( + let (s, _state): (Option>, Option<()>) = Permissive::from_route_part( "".to_string(), Some(()), ); - assert_eq!(s, Some(Some("".to_string()))) + assert_eq!(s, Some(Permissive(Some("".to_string())))) } } diff --git a/tests/macro_test/src/lib.rs b/tests/macro_test/src/lib.rs index b345d57..9543636 100644 --- a/tests/macro_test/src/lib.rs +++ b/tests/macro_test/src/lib.rs @@ -1,6 +1,7 @@ #[cfg(test)] mod tests { use yew_router::{prelude::Route, Switch}; + use yew_router::switch::Permissive; #[test] fn single_enum_variant() { @@ -9,7 +10,7 @@ mod tests { #[to = "/variant"] Variant, } - let route: Route = Route::from("/variant"); + let route = Route::new_no_state("/variant"); let switched = Test::switch(route).expect("should produce item"); assert_eq!(switched, Test::Variant) } @@ -21,12 +22,12 @@ mod tests { #[to = "/variant"] Variant(String), } - let route: Route = Route::from("/variant"); + let route = Route::new_no_state("/variant"); assert!( Test::switch(route).is_none(), "there should not be a way to ever create this variant." ); - let route: Route = Route::from("/variant/some/stuff"); + let route = Route::new_no_state("/variant/some/stuff"); assert!( Test::switch(route).is_none(), "there should not be a way to ever create this variant." @@ -40,7 +41,7 @@ mod tests { #[to = "/variant/{item}"] Variant { item: String }, } - let route: Route = Route::from("/variant/thing"); + let route = Route::new_no_state("/variant/thing"); let switched = Test::switch(route).expect("should produce item"); assert_eq!( switched, @@ -57,7 +58,7 @@ mod tests { #[to = "/variant/{item}"] Variant(String), } - let route: Route = Route::from("/variant/thing"); + let route = Route::new_no_state("/variant/thing"); let switched = Test::switch(route).expect("should produce item"); assert_eq!(switched, Test::Variant("thing".to_string())) } @@ -69,7 +70,7 @@ mod tests { #[to = "/variant/{}/{}"] // For unnamed variants, the names don't matter at all Variant(String, String), } - let route: Route = Route::from("/variant/thing/other"); + let route = Route::new_no_state("/variant/thing/other"); let switched = Test::switch(route).expect("should produce item"); assert_eq!( switched, @@ -84,7 +85,7 @@ mod tests { #[to = "/variant/{item1}/{item2}"] Variant { item1: String, item2: String }, } - let route: Route = Route::from("/variant/thing/other"); + let route = Route::new_no_state("/variant/thing/other"); let switched = Test::switch(route).expect("should produce item"); assert_eq!( switched, @@ -102,7 +103,7 @@ mod tests { #[to = "/variant{item}"] Variant { item: String }, } - let route: Route = Route::from("/variantthing"); + let route = Route::new_no_state("/variantthing"); let switched = Test::switch(route).expect("should produce item"); assert_eq!( switched, @@ -119,7 +120,7 @@ mod tests { #[to = "/variant{item}stuff"] Variant { item: String }, } - let route: Route = Route::from("/variantthingstuff"); + let route = Route::new_no_state("/variantthingstuff"); let switched = Test::switch(route).expect("should produce item"); assert_eq!( switched, @@ -136,7 +137,7 @@ mod tests { #[to = "/variant!"] Variant, } - let route: Route = Route::from("/variant/"); + let route = Route::new_no_state("/variant/"); assert!(Test::switch(route).is_none()); } @@ -149,7 +150,7 @@ mod tests { #[to = "/variant/stuff"] Variant2, } - let route: Route = Route::from("/variant/stuff"); + let route = Route::new_no_state("/variant/stuff"); let switched = Test::switch(route).expect("should produce item"); assert_eq!( switched, @@ -167,7 +168,7 @@ mod tests { #[to = "/variant/stuff"] Variant2, } - let route: Route = Route::from("/variant/stuff"); + let route = Route::new_no_state("/variant/stuff"); let switched = Test::switch(route).expect("should produce item"); assert_eq!( switched, @@ -183,7 +184,7 @@ mod tests { #[to = "/variant/{item}"] Variant(usize), } - let route: Route = Route::from("/variant/42"); + let route = Route::new_no_state("/variant/42"); let switched = Test::switch(route).expect("should produce item"); assert_eq!(switched, Test::Variant(42)) } @@ -195,7 +196,7 @@ mod tests { #[to = "/variant/{item}"] Variant(usize), } - let route: Route = Route::from("/variant/-42"); + let route = Route::new_no_state("/variant/-42"); assert!(Test::switch(route).is_none()); } @@ -206,21 +207,21 @@ mod tests { #[to = "/variant/{item}"] Variant(isize), } - let route: Route = Route::from("/variant/-42"); + let route = Route::new_no_state("/variant/-42"); let switched = Test::switch(route).expect("should produce item"); assert_eq!(switched, Test::Variant(-42)) } #[test] - fn single_enum_variant_missing_cap_produces_option_none() { + fn single_enum_variant_missing_cap_produces_permissive_option_none() { #[derive(Debug, Switch, PartialEq, Clone)] pub enum Test { #[to = "/variant"] - Variant(Option), + Variant(Permissive), } - let route: Route = Route::from("/variant"); + let route = Route::new_no_state("/variant"); let switched = Test::switch(route).expect("should produce item"); - assert_eq!(switched, Test::Variant(None)) + assert_eq!(switched, Test::Variant(Permissive(None))) } // TODO allow missing is a little broken at the moment. @@ -244,7 +245,7 @@ mod tests { #[to = "/"] Variant, } - let route: Route = Route::from("/"); + let route = Route::new_no_state("/"); let switched = Test::switch(route).expect("should produce item"); assert_eq!(switched, Test::Variant) } @@ -256,7 +257,7 @@ mod tests { #[to = "{cap}"] Variant(String), } - let route: Route = Route::from("hello"); + let route = Route::new_no_state("hello"); let switched = Test::switch(route).expect("should produce item"); assert_eq!(switched, Test::Variant("hello".to_string())) } @@ -268,7 +269,7 @@ mod tests { #[to = "{}"] Variant(String), } - let route: Route = Route::from("hello"); + let route = Route::new_no_state("hello"); let switched = Test::switch(route).expect("should produce item"); assert_eq!(switched, Test::Variant("hello".to_string())) } @@ -280,7 +281,7 @@ mod tests { #[to = "{2:cap}"] Variant(String), } - let route: Route = Route::from("hello/there"); + let route = Route::new_no_state("hello/there"); let switched = Test::switch(route).expect("should produce item"); assert_eq!(switched, Test::Variant("hello/there".to_string())) } @@ -292,7 +293,7 @@ mod tests { #[to = "{2}"] Variant(String), } - let route: Route = Route::from("hello/there"); + let route = Route::new_no_state("hello/there"); let switched = Test::switch(route).expect("should produce item"); assert_eq!(switched, Test::Variant("hello/there".to_string())) } @@ -304,7 +305,7 @@ mod tests { #[to = "{*:cap}"] Variant(String), } - let route: Route = Route::from("hello/there"); + let route = Route::new_no_state("hello/there"); let switched = Test::switch(route).expect("should produce item"); assert_eq!(switched, Test::Variant("hello/there".to_string())) } @@ -316,7 +317,7 @@ mod tests { #[to = "{*}"] Variant(String), } - let route: Route = Route::from("hello/there"); + let route = Route::new_no_state("hello/there"); let switched = Test::switch(route).expect("should produce item"); assert_eq!(switched, Test::Variant("hello/there".to_string())) } @@ -328,7 +329,7 @@ mod tests { #[to = "?query={hello}"] Variant(String), } - let route: Route = Route::from("?query=lorem"); + let route = Route::new_no_state("?query=lorem"); let switched = Test::switch(route).expect("should produce item"); assert_eq!(switched, Test::Variant("lorem".to_string())) } @@ -340,7 +341,7 @@ mod tests { #[to = "?query={}"] Variant(String), } - let route: Route = Route::from("?query=lorem"); + let route = Route::new_no_state("?query=lorem"); let switched = Test::switch(route).expect("should produce item"); assert_eq!(switched, Test::Variant("lorem".to_string())) } @@ -352,7 +353,7 @@ mod tests { #[to = "#fragment"] Variant, } - let route: Route = Route::from("#fragment"); + let route = Route::new_no_state("#fragment"); let switched = Test::switch(route).expect("should produce item"); assert_eq!(switched, Test::Variant) } @@ -364,7 +365,7 @@ mod tests { #[to = "#{cap}ipsum{cap}"] Variant(String, String), } - let route: Route = Route::from("#loremipsumdolor"); + let route = Route::new_no_state("#loremipsumdolor"); let switched = Test::switch(route).expect("should produce item"); assert_eq!( switched, @@ -379,7 +380,7 @@ mod tests { #[to = "#{}ipsum{}"] Variant(String, String), } - let route: Route = Route::from("#loremipsumdolor"); + let route = Route::new_no_state("#loremipsumdolor"); let switched = Test::switch(route).expect("should produce item"); assert_eq!( switched, @@ -394,7 +395,7 @@ mod tests { #[to = "/escape!!"] Variant, } - let route: Route = Route::from("/escape!"); + let route = Route::new_no_state("/escape!"); let switched = Test::switch(route).expect("should produce item"); assert_eq!(switched, Test::Variant) } @@ -406,7 +407,7 @@ mod tests { #[to = "/escape{{}}a"] Variant, } - let route: Route = Route::from("/escape{}a"); + let route = Route::new_no_state("/escape{}a"); let switched = Test::switch(route).expect("should produce item"); assert_eq!(switched, Test::Variant) } @@ -421,7 +422,7 @@ mod tests { #[to = "#/lorem"] Variant, } - let route: Route = Route::from("#/lorem"); + let route = Route::new_no_state("#/lorem"); Test::switch(route).expect("should produce item"); } @@ -432,7 +433,7 @@ mod tests { #[to = "#/lorem=ipsum"] Variant, } - let route: Route = Route::from("#/lorem=ipsum"); + let route = Route::new_no_state("#/lorem=ipsum"); Test::switch(route).expect("should produce item"); } @@ -443,7 +444,7 @@ mod tests { #[to = "#/lorem={ipsum}"] Variant { ipsum: String }, } - let route: Route = Route::from("#/lorem=dolor"); + let route = Route::new_no_state("#/lorem=dolor"); let switched = Test::switch(route).expect("should produce item"); assert_eq!( switched,