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
extern crate proc_macro;
use proc_macro::TokenStream;

mod switch;

/// Implements the `Switch` trait based on attributes present on the struct or enum variants.
///
/// If deriving an enum, each variant should have a `#[to = ""]` attribute,
/// and if deriving a struct, the struct itself should have a `#[to = ""]` attribute.
///
/// Inside the `""` you should put your **route matcher string**.
/// At its simplest, the route matcher string will create your variant/struct if it exactly matches the browser's route.
/// If the route in the url bar is `http://yoursite.com/some/route` and your route matcher string
/// for an enum variant is `/some/route`, then that variant will be created when `switch()` is called with the route.
///
/// But the route matcher has other capabilities.
/// If you want to capture data from the route matcher string, for example, extract an id or user name from the route,
/// you can use `{field_name}` to capture data from the route.
/// For example, `#[to = "/route/{id}"]` will capture the content after "/route/",
/// and if the associated variant is defined as `Route{id: usize}`, then the string that was captured will be
/// transformed into a `usize`.
/// If the conversion fails, then the match won't succeed and the next variant will be tried instead.
///
/// There are also `{*:field_name}` and `{3:field_name}` types of capture sections that will capture
/// _everything_, and the next 3 path sections respectively.
/// `{1:field_name}` is the same as `{field_name}`.
///
/// Tuple-structs and Tuple-enum-variants are also supported.
/// If you don't want to specify keys that don't correspond to any specific field,
/// `{}`, `{*}`, and `{4}` also denote valid capture sections when used on structs and variants without named fields.
/// In datastructures without field names, the captures will be assigned in order - left to right.
///
/// # Note
/// It should be mentioned that the derived function for matching will try enum variants in order,
/// from top to bottom, and that the whole route doesn't need to be matched by the route
/// matcher string in order for the match to succeed.
/// What is meant by this is that `[to = "/"]` will match "/", but also "/anything/else",
/// because as soon as the "/" is satisfied, that is considered a match.
///
/// This can be mitigated by specifying a `!` at the end of your route to inform the matcher that if
/// any characters are left after matching the route matcher string, the match should fail.
/// This means that `[to = "/!"]` will match "/" and _only_ "/".
///
/// -----
/// There are other attributes as well.
/// `#[rest]`, `#[rest="field_name"]` and `#[end]` attributes exist as well.
/// `#[rest]` and `#[rest="field_name"]` are equivalent to `{*}` and `{*:field_name}` respectively.
/// `#[end]` is equivalent to `!`.
/// The `#[rest]` attributes are good if you just want to delegate the whole matching of a variant to a specific
/// wrapped struct or enum that also implements `Switch`.
///
/// ------
/// # Example
/// ```
/// use yew_router_min::Switch;
///
/// #[derive(Switch, Clone)]
/// enum AppRoute {
///     #[to = "/some/simple/route"]
///     SomeSimpleRoute,
///     #[to = "/capture/{}"]
///     Capture(String),
///     #[to = "/named/capture/{name}"]
///     NamedCapture { name: String },
///     #[to = "/convert/{id}"]
///     Convert { id: usize },
///     #[rest] // shorthand for #[to="{*}"]
///     Inner(InnerRoute),
/// }
///
/// #[derive(Switch, Clone)]
/// #[to = "/inner/route/{first}/{second}"]
/// struct InnerRoute {
///     first: String,
///     second: String,
/// }
/// ```
/// Check out the examples directory in the repository to see some more usages of the routing syntax.
#[proc_macro_derive(Switch, attributes(to, rest, end))]
pub fn switch(tokens: TokenStream) -> TokenStream {
    crate::switch::switch_impl(tokens)
}

#[proc_macro_attribute]
pub fn to(_: TokenStream, _: TokenStream) -> TokenStream {
    TokenStream::new()
}

#[proc_macro_attribute]
pub fn rest(_: TokenStream, _: TokenStream) -> TokenStream {
    TokenStream::new()
}

#[proc_macro_attribute]
pub fn end(_: TokenStream, _: TokenStream) -> TokenStream {
    TokenStream::new()
}