1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
//! Parses routes into enums or structs. /// Derivable routing trait that allows instances of implementors to be constructed from Routes. /// /// # Note /// Don't try to implement this yourself, rely on the derive macro. /// /// # Example /// ``` /// use yew_router_min::Switch; /// #[derive(Debug, Switch, PartialEq)] /// enum TestEnum { /// #[to = "/test/route"] /// TestRoute, /// #[to = "/capture/string/{path}"] /// CaptureString { path: String }, /// #[to = "/capture/number/{num}"] /// CaptureNumber { num: usize }, /// #[to = "/capture/unnamed/{doot}"] /// CaptureUnnamed(String), /// } /// /// assert_eq!( /// TestEnum::from_path("/test/route"), /// Some(TestEnum::TestRoute) /// ); /// assert_eq!( /// TestEnum::from_path("/capture/string/lorem"), /// Some(TestEnum::CaptureString { /// path: "lorem".to_string() /// }) /// ); /// assert_eq!( /// TestEnum::from_path("/capture/number/22"), /// Some(TestEnum::CaptureNumber { num: 22 }) /// ); /// assert_eq!( /// TestEnum::from_path("/capture/unnamed/lorem"), /// Some(TestEnum::CaptureUnnamed("lorem".to_string())) /// ); /// ``` pub trait Switch: Sized { /// Based on a route, possibly produce an itself. fn from_path(path: &str) -> Option<Self>; /// Parses route. fn from_route(part: String) -> Option<Self> { Self::from_path(&part) } } /// Wrapper that requires that an implementor of Switch must start with a `/`. /// /// This is needed for any non-derived type provided by yew-router to be used by itself. /// /// This is because route strings will almost always start with `/`, so in order to get a std type /// with the `rest` attribute, without a specified leading `/`, this wrapper is needed. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct LeadingSlash<T>(pub T); impl<U: Switch> Switch for LeadingSlash<U> { fn from_path(part: &str) -> Option<Self> { if part.starts_with('/') { U::from_path(&part[1..]).map(LeadingSlash) } else { None } } } /// 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<T: std::fmt::Debug>(pub Option<T>); impl<U: Switch + std::fmt::Debug> Switch for AllowMissing<U> { fn from_path(part: &str) -> Option<Self> { let inner = U::from_path(&part); if inner.is_some() { Some(AllowMissing(inner)) } else if part == "" || part.starts_with('/') || part.starts_with('?') || part.starts_with('&') || part.starts_with('#') { Some(AllowMissing(None)) } else { None } } } impl<T: std::str::FromStr> Switch for T { fn from_path(s: &str) -> Option<Self> { ::std::str::FromStr::from_str(s).ok() } }