40
40
//! - other syntaxes, maybe something like `key: value`
41
41
use std:: fmt:: Display ;
42
42
43
- use proc_macro2:: { Literal , Span } ;
44
43
#[ doc( hidden) ]
45
44
pub use attribute_derive_macro:: Attribute ;
45
+ use proc_macro2:: { Literal , Span , TokenStream } ;
46
46
use syn:: {
47
47
bracketed, parse:: Parse , punctuated:: Punctuated , Expr , Lit , LitBool , LitByteStr , LitChar ,
48
48
LitFloat , LitInt , LitStr , Path , Result , Token , Type , __private:: ToTokens , parse_quote,
@@ -113,7 +113,7 @@ where
113
113
pub trait ConvertParsed
114
114
where
115
115
Self : Sized ,
116
- Self :: Type : Error ,
116
+ Self :: Type : Error + Clone ,
117
117
{
118
118
/// The type this can be converted from
119
119
type Type ;
@@ -128,14 +128,52 @@ where
128
128
}
129
129
/// The default value, this is necessary to implement the implicit default behavior of
130
130
/// [`Option`]
131
+ ///
132
+ /// This is necessary as the [`Default`] trait cannot be used in expanded code, but normally you
133
+ /// can easily implement it using it:
134
+ /// ```
135
+ /// # use attribute_derive::ConvertParsed;
136
+ /// # use syn::{Result, LitBool};
137
+ /// # #[derive(Default)]
138
+ /// # struct bool;
139
+ /// impl ConvertParsed for bool {
140
+ /// # type Type = LitBool;
141
+ /// # fn convert(value: Self::Type) -> Result<Self> {
142
+ /// # unimplemented!()
143
+ /// # }
144
+ /// fn default() -> Self {
145
+ /// Default::default()
146
+ /// }
147
+ /// }
148
+ /// ```
131
149
fn default ( ) -> Self {
132
150
unreachable ! ( "default_by_default should only return true if this is overridden" )
133
151
}
134
- /// Should values of this type be able to be defined as flag i.e. just `#[attr(default)]`
135
- /// instead of `#[attr(default=true)]`
152
+ /// Returns the value when this type is specified as flag i.e. just `#[attr(default)]`
153
+ /// instead of `#[attr(default=true)]`. This relies on [`Self::default`].
136
154
fn as_flag ( ) -> Option < Self :: Type > {
137
155
None
138
156
}
157
+ /// Should values of this type be aggregated instead of conflict if specified multiple times
158
+ ///
159
+ /// Currently this is only implemented for [`Arrays`](Array)
160
+ #[ allow( unused) ]
161
+ fn aggregate (
162
+ this : Option < Self :: Type > ,
163
+ other : Option < Self :: Type > ,
164
+ error1 : & str ,
165
+ error2 : & str ,
166
+ ) -> Result < Option < Self :: Type > > {
167
+ match ( this, other) {
168
+ ( None , value) => Ok ( value) ,
169
+ ( value, None ) => Ok ( value) ,
170
+ ( Some ( this) , Some ( other) ) => {
171
+ let mut error = this. error ( error1) ;
172
+ syn:: Error :: combine ( & mut error, other. error ( error2) ) ;
173
+ Err ( error)
174
+ }
175
+ }
176
+ }
139
177
}
140
178
141
179
/// Helper trait to generate sensible errors
@@ -156,7 +194,8 @@ where
156
194
157
195
/// Macro to easily implement [`ConvertParsed`] for syn types
158
196
macro_rules! convert_parsed {
159
- ( $type: path) => {
197
+ ( $( #[ $meta: meta] ) * $type: path) => {
198
+ $( #[ $meta] ) *
160
199
impl ConvertParsed for $type {
161
200
type Type = $type;
162
201
fn convert( s: Self ) -> Result <Self > {
@@ -206,7 +245,7 @@ macro_rules! convert_parsed {
206
245
impl < Output , Parsed > ConvertParsed for Option < Output >
207
246
where
208
247
Output : ConvertParsed < Type = Parsed > ,
209
- Parsed : Error ,
248
+ Parsed : Error + Clone ,
210
249
{
211
250
type Type = Parsed ;
212
251
fn convert ( s : Parsed ) -> Result < Self > {
@@ -225,11 +264,29 @@ where
225
264
impl < Output , Parsed > ConvertParsed for Vec < Output >
226
265
where
227
266
Output : ConvertParsed < Type = Parsed > ,
267
+ Parsed : Clone ,
228
268
{
229
269
type Type = Array < Parsed > ;
230
270
fn convert ( array : Array < Parsed > ) -> Result < Self > {
231
271
array. data . into_iter ( ) . map ( ConvertParsed :: convert) . collect ( )
232
272
}
273
+ fn aggregate (
274
+ this : Option < Self :: Type > ,
275
+ other : Option < Self :: Type > ,
276
+ _: & str ,
277
+ _: & str ,
278
+ ) -> Result < Option < Self :: Type > > {
279
+ Ok ( match ( this, other) {
280
+ ( None , None ) => None ,
281
+ ( None , value) => value,
282
+ ( value, None ) => value,
283
+ ( Some ( mut this) , Some ( other) ) => {
284
+ this. data . extend_from_slice ( & other. data ) ;
285
+ this. span = this. span . join ( other. span ) . unwrap_or ( this. span ) ;
286
+ Some ( this)
287
+ }
288
+ } )
289
+ }
233
290
}
234
291
235
292
impl ConvertParsed for bool {
@@ -254,6 +311,7 @@ impl ConvertParsed for bool {
254
311
255
312
/// Helper struct to parse array literals:
256
313
/// `[a, b, c]`
314
+ #[ derive( Clone ) ]
257
315
pub struct Array < T > {
258
316
data : Vec < T > ,
259
317
span : Span ,
@@ -286,6 +344,16 @@ convert_parsed!(Lit);
286
344
convert_parsed ! [ LitStr , LitByteStr , LitChar , LitInt , LitFloat , LitBool , Literal ] ;
287
345
convert_parsed ! ( Expr ) ;
288
346
347
+ // TODO make this warning better visable
348
+ convert_parsed ! {
349
+ /// Try to avoid using this, as it will consume everything behind, so it needs to be defined as the
350
+ /// last parameter.
351
+ ///
352
+ /// In the future there might be something to allow better handling of this (maybe by puttin it
353
+ /// into `()`)
354
+ TokenStream
355
+ }
356
+
289
357
convert_parsed ! ( LitStr => String : LitStr :: value) ;
290
358
// TODO convert_parsed!(LitByteStr => Vec<u8>: LitByteStr::value);
291
359
convert_parsed ! ( LitChar => char : LitChar :: value) ;
0 commit comments