@@ -22,7 +22,7 @@ use std::path::PathBuf;
22
22
#[ cfg( feature = "rustc-hash" ) ]
23
23
use rustc_hash:: FxHashMap as HashMap ;
24
24
use serde_derive:: { Deserialize , Serialize } ;
25
-
25
+ use serde :: de :: Error ;
26
26
27
27
/// The version of JSON output that this crate represents.
28
28
///
@@ -201,7 +201,7 @@ pub struct Item {
201
201
pub inner : ItemEnum ,
202
202
}
203
203
204
- #[ derive( Clone , Debug , PartialEq , Eq , Serialize , Deserialize ) ]
204
+ #[ derive( Clone , Debug , PartialEq , Eq , Serialize ) ]
205
205
#[ serde( rename_all = "snake_case" ) ]
206
206
/// An attribute, e.g. `#[repr(C)]`
207
207
///
@@ -242,11 +242,108 @@ pub enum Attribute {
242
242
/// 1. A HIR debug printing, like `"#[attr = Optimize(Speed)]"`
243
243
/// 2. The attribute as it appears in source form, like
244
244
/// `"#[optimize(speed)]"`.
245
- // XXX: This variant must be last in the enum because it is untagged.
246
- #[ serde( untagged) ]
247
245
Other ( String ) ,
248
246
}
249
247
248
+ impl < ' de > serde:: Deserialize < ' de > for Attribute {
249
+ fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
250
+ where
251
+ D : serde:: Deserializer < ' de > ,
252
+ {
253
+ let s = String :: deserialize ( deserializer) ?;
254
+
255
+ // Strip #[ and ] if present
256
+ let cleaned = s. trim_start_matches ( "#[" )
257
+ . trim_end_matches ( "]" )
258
+ . trim ( ) ;
259
+
260
+ // Now match on the cleaned string
261
+ Ok ( match cleaned {
262
+ "non_exhaustive" => Attribute :: NonExhaustive ,
263
+ s if s. starts_with ( "must_use" ) => {
264
+ // Parse reason if present
265
+ let reason = if s. len ( ) > "must_use" . len ( ) {
266
+ Some ( s[ "must_use" . len ( ) ..] . trim_matches ( |c| c == '(' || c == ')' || c == '"' ) . to_string ( ) )
267
+ } else {
268
+ None
269
+ } ;
270
+ Attribute :: MustUse { reason }
271
+ } ,
272
+ s if s. starts_with ( "export_name" ) => {
273
+ let name = s[ "export_name" . len ( ) ..] . trim_matches ( |c| c == '=' || c == ' ' || c == '"' ) . to_string ( ) ;
274
+ Attribute :: ExportName ( name)
275
+ } ,
276
+
277
+ s if s. starts_with ( "export_name" ) => {
278
+ let name = s[ "export_name" . len ( ) ..] . trim_matches ( |c| c == '=' || c == ' ' || c == '"' ) . to_string ( ) ;
279
+ Attribute :: ExportName ( name)
280
+ } ,
281
+
282
+ s if s. starts_with ( "link_section" ) => {
283
+ let section = s[ "link_section" . len ( ) ..] . trim_matches ( |c| c == '=' || c == ' ' || c == '"' ) . to_string ( ) ;
284
+ Attribute :: LinkSection ( section)
285
+ } ,
286
+
287
+ "automatically_derived" => Attribute :: AutomaticallyDerived ,
288
+
289
+ s if s. starts_with ( "repr" ) => {
290
+ let repr_str = s[ "repr" . len ( ) ..] . trim_matches ( |c| c == '(' || c == ')' ) . trim ( ) ;
291
+ let parts: Vec < & str > = repr_str. split ( ',' ) . map ( str:: trim) . collect ( ) ;
292
+
293
+ let mut repr = AttributeRepr {
294
+ kind : ReprKind :: C , // Will be overwritten
295
+ align : None ,
296
+ packed : None ,
297
+ int : None ,
298
+ } ;
299
+
300
+ for part in parts {
301
+ if part. starts_with ( "align(" ) {
302
+ let align_str = part. trim_start_matches ( "align(" ) . trim_end_matches ( ')' ) ;
303
+ repr. align = Some ( align_str. parse ( ) . map_err ( D :: Error :: custom) ?) ;
304
+ } else if part. starts_with ( "packed(" ) {
305
+ let packed_str = part. trim_start_matches ( "packed(" ) . trim_end_matches ( ')' ) ;
306
+ repr. packed = Some ( packed_str. parse ( ) . map_err ( D :: Error :: custom) ?) ;
307
+ } else if part == "C" {
308
+ repr. kind = ReprKind :: C ;
309
+ } else if part == "transparent" {
310
+ repr. kind = ReprKind :: Transparent ;
311
+ } else if [ "i8" , "i16" , "i32" , "i64" , "i128" , "isize" ,
312
+ "u8" , "u16" , "u32" , "u64" , "u128" , "usize" ] . contains ( & part) {
313
+ repr. int = Some ( part. to_string ( ) ) ;
314
+ }
315
+ // Add other ReprKind variants as needed
316
+ }
317
+
318
+ Attribute :: Repr ( repr)
319
+ } ,
320
+
321
+ "no_mangle" => Attribute :: NoMangle ,
322
+
323
+ s if s. starts_with ( "target_feature" ) => {
324
+ let features_str = s[ "target_feature" . len ( ) ..] . trim_matches ( |c| c == '(' || c == ')' ) . trim ( ) ;
325
+ let enable: Vec < String > = features_str
326
+ . split ( ',' )
327
+ . filter_map ( |feature| {
328
+ let feature = feature. trim ( ) ;
329
+ if feature. starts_with ( "enable = " ) {
330
+ Some ( feature[ "enable = " . len ( ) ..] . trim_matches ( '"' ) . to_string ( ) )
331
+ } else {
332
+ None
333
+ }
334
+ } )
335
+ . collect ( ) ;
336
+ Attribute :: TargetFeature { enable }
337
+ } ,
338
+
339
+
340
+ // Default case
341
+ _ => Attribute :: Other ( s. to_string ( ) ) ,
342
+ } )
343
+ }
344
+ }
345
+
346
+
250
347
#[ derive( Clone , Debug , PartialEq , Eq , Serialize , Deserialize ) ]
251
348
/// The contents of a `#[repr(...)]` attribute.
252
349
///
0 commit comments