-
-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathlib.rs
More file actions
149 lines (146 loc) · 5.37 KB
/
Copy pathlib.rs
File metadata and controls
149 lines (146 loc) · 5.37 KB
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use syn::parse_macro_input;
mod fragment;
mod merge;
/// Derives [`Merge`](trait.Merge.html) for a given struct or enum, by merging each field individually.
///
/// For enums, all values of the previous variant are discarded if the variant is changed, even if the same field exists in both variants.
///
/// # Supported attributes
///
/// ## `#[merge(bound = "...")]`
///
/// This attribute can be used to specify additional `where` clauses on the derived trait implementation.
/// Bounds specified on the struct itself are automatically inherited for the generated implementation, and
/// do not need to be repeated here.
///
/// For example, this:
///
/// ```
/// # use stackable_operator::config::merge::Merge;
/// #[derive(Merge)]
/// #[merge(bound = "T: Merge")]
/// struct Wrapper<T>
/// where
/// T: Clone,
/// {
/// inner: T,
/// }
/// ```
///
/// Expands to (roughly) the following:
///
/// ```
/// # use stackable_operator::config::merge::Merge;
/// struct Wrapper<T>
/// where
/// T: Clone,
/// {
/// inner: T,
/// }
/// impl<T> Merge for Wrapper<T>
/// where
/// T: Clone, // this clause was inherited from the struct
/// T: Merge, // this clause was specified using #[merge(bound)]
/// {
/// fn merge(&mut self, defaults: &Self) {
/// self.inner.merge(&defaults.inner);
/// }
/// }
/// ```
///
/// ## `#[merge(path_overrides(merge = "..."))]`
///
/// This attribute can be used to override the path to the module containing the [`Merge`](trait.Merge.html) trait, if it is reexported
/// or the `stackable_operator` crate is renamed.
#[proc_macro_derive(Merge, attributes(merge))]
pub fn derive_merge(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
merge::derive(parse_macro_input!(input)).into()
}
/// Creates a [fragment type](index.html) for the given type, and implements [`FromFragment`](trait.FromFragment.html).
///
/// This macro implements "deep optionality", meaning that each field is replaced by its `Fragment` variant. For example, this type:
///
/// ```ignore
/// #[derive(Fragment)]
/// struct Foo {
/// atomic: u32,
/// nested: Bar,
/// }
/// ```
///
/// would generate the following output:
///
/// ```ignore
/// struct FooFragment {
/// atomic: u32::Fragment, // = Option<u32>
/// nested: Bar::Fragment, // = BarFragment, assuming that Bar is also #[derive(Fragment)]
/// }
///
/// impl FromFragment for Foo {
/// // no need for Option since the value is already deeply optional
/// type Fragment = FooFragment;
/// type RequiredFragment = FooFragment;
///
/// // snipped support code
/// }
/// ```
///
/// # Supported Attributes
///
/// ## `#[fragment_attrs(...)]`
///
/// This attribute can be used to forward attributes to the generated fragment. For example, `#[fragment_attrs(derive(Default))]` derives [`Default`] for the fragment type.
///
/// This can be specified on both the struct itself and the field, and will be forwarded to the corresponding location on the generated fragment.
///
/// ## `#[fragment(bound = "...")]`
///
/// This attribute can be used to specify additional `where` clauses on the derived fragment and trait implementation. Bounds specified on the struct itself
/// are automatically inherited for the generated implementation, and do not need to be repeated here.
///
/// ## `#[fragment(path_overrides(fragment = "..."))]`
///
/// This attribute can be used to override the path to the module containing the [`FromFragment`](trait.FromFragment.html) trait, if it is reexported
/// or the `stackable_operator` crate is renamed.
///
/// # Generics
///
/// This macro supports generic types, but there are some caveats to be aware of.
///
/// ## Fragment macro bounds
///
/// The `Fragment` macro does not automatically insert any type bounds, they must be specified manually. Typically, this means adding the attribute
/// `#[fragment(bound = "T: FromFragment")]` to the type.
///
/// ## Interactions with other derive macros
///
/// Arbitrary other macros can be specified for the generated fragment type. However, many macros automatically add the bound `where T: Trait`. This assumption makes sense
/// for most types (with the assumption that each type is used "directly" in the struct definition).
///
/// However, fragment types use `T::Fragment` instead, and the generated bounds must be overridden to reflect this. The exact convention used to do this is going to vary
/// between macros, but typically they will take an attribute such as `#[trait(bound = "T::Fragment: Trait")]`.
///
/// ### `std` traits
///
/// `std`'s built-in derive macros (such as [`Default`]) do not take any configuration. Instead, use [`Derivative`](https://mcarton.github.io/rust-derivative/latest/index.html),
/// which supports custom bounds using the attribute convention `#[derivative(Trait(bound = "T::Fragment: Trait"))]`.
///
/// ### `serde`
///
/// Serde uses the `#[serde]` attribute to configure both `Serialize` and `Deserialize`. However, bounds must be configured separately for the two. Hence, the correct
/// bound would be:
///
/// ```ignore
/// #[serde(bound(
/// serialize = "T::Fragment: Serialize",
/// deserialize = "T::Fragment: Deserialize<'de>",
/// ))]
/// ```
///
/// # Enums
///
/// Enums are not currently supported.
#[proc_macro_derive(Fragment, attributes(fragment, fragment_attrs))]
pub fn derive_fragment(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
fragment::derive(parse_macro_input!(input)).into()
}