4040//! - other syntaxes, maybe something like `key: value`
4141use std:: fmt:: Display ;
4242
43- use proc_macro2:: { Literal , Span } ;
4443#[ doc( hidden) ]
4544pub use attribute_derive_macro:: Attribute ;
45+ use proc_macro2:: { Literal , Span , TokenStream } ;
4646use syn:: {
4747 bracketed, parse:: Parse , punctuated:: Punctuated , Expr , Lit , LitBool , LitByteStr , LitChar ,
4848 LitFloat , LitInt , LitStr , Path , Result , Token , Type , __private:: ToTokens , parse_quote,
@@ -113,7 +113,7 @@ where
113113pub trait ConvertParsed
114114where
115115 Self : Sized ,
116- Self :: Type : Error ,
116+ Self :: Type : Error + Clone ,
117117{
118118 /// The type this can be converted from
119119 type Type ;
@@ -128,14 +128,52 @@ where
128128 }
129129 /// The default value, this is necessary to implement the implicit default behavior of
130130 /// [`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+ /// ```
131149 fn default ( ) -> Self {
132150 unreachable ! ( "default_by_default should only return true if this is overridden" )
133151 }
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`].
136154 fn as_flag ( ) -> Option < Self :: Type > {
137155 None
138156 }
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+ }
139177}
140178
141179/// Helper trait to generate sensible errors
@@ -156,7 +194,8 @@ where
156194
157195/// Macro to easily implement [`ConvertParsed`] for syn types
158196macro_rules! convert_parsed {
159- ( $type: path) => {
197+ ( $( #[ $meta: meta] ) * $type: path) => {
198+ $( #[ $meta] ) *
160199 impl ConvertParsed for $type {
161200 type Type = $type;
162201 fn convert( s: Self ) -> Result <Self > {
@@ -206,7 +245,7 @@ macro_rules! convert_parsed {
206245impl < Output , Parsed > ConvertParsed for Option < Output >
207246where
208247 Output : ConvertParsed < Type = Parsed > ,
209- Parsed : Error ,
248+ Parsed : Error + Clone ,
210249{
211250 type Type = Parsed ;
212251 fn convert ( s : Parsed ) -> Result < Self > {
@@ -225,11 +264,29 @@ where
225264impl < Output , Parsed > ConvertParsed for Vec < Output >
226265where
227266 Output : ConvertParsed < Type = Parsed > ,
267+ Parsed : Clone ,
228268{
229269 type Type = Array < Parsed > ;
230270 fn convert ( array : Array < Parsed > ) -> Result < Self > {
231271 array. data . into_iter ( ) . map ( ConvertParsed :: convert) . collect ( )
232272 }
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+ }
233290}
234291
235292impl ConvertParsed for bool {
@@ -254,6 +311,7 @@ impl ConvertParsed for bool {
254311
255312/// Helper struct to parse array literals:
256313/// `[a, b, c]`
314+ #[ derive( Clone ) ]
257315pub struct Array < T > {
258316 data : Vec < T > ,
259317 span : Span ,
@@ -286,6 +344,16 @@ convert_parsed!(Lit);
286344convert_parsed ! [ LitStr , LitByteStr , LitChar , LitInt , LitFloat , LitBool , Literal ] ;
287345convert_parsed ! ( Expr ) ;
288346
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+
289357convert_parsed ! ( LitStr => String : LitStr :: value) ;
290358// TODO convert_parsed!(LitByteStr => Vec<u8>: LitByteStr::value);
291359convert_parsed ! ( LitChar => char : LitChar :: value) ;
0 commit comments