• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Fuchsia Authors
2 //
3 // Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4 // <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6 // This file may not be copied, modified, or distributed except according to
7 // those terms.
8 
9 use proc_macro2::{Span, TokenStream};
10 use quote::ToTokens;
11 use syn::{Data, DataEnum, DataStruct, DataUnion, Field, Ident, Index, Type, Visibility};
12 
13 pub(crate) trait DataExt {
14     /// Extracts the names and types of all fields. For enums, extracts the names
15     /// and types of fields from each variant. For tuple structs, the names are
16     /// the indices used to index into the struct (ie, `0`, `1`, etc).
17     ///
18     /// TODO: Extracting field names for enums doesn't really make sense. Types
19     /// makes sense because we don't care about where they live - we just care
20     /// about transitive ownership. But for field names, we'd only use them when
21     /// generating is_bit_valid, which cares about where they live.
fields(&self) -> Vec<(&Visibility, TokenStream, &Type)>22     fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)>;
23 
variants(&self) -> Vec<Vec<(&Visibility, TokenStream, &Type)>>24     fn variants(&self) -> Vec<Vec<(&Visibility, TokenStream, &Type)>>;
25 
tag(&self) -> Option<Ident>26     fn tag(&self) -> Option<Ident>;
27 }
28 
29 impl DataExt for Data {
fields(&self) -> Vec<(&Visibility, TokenStream, &Type)>30     fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> {
31         match self {
32             Data::Struct(strc) => strc.fields(),
33             Data::Enum(enm) => enm.fields(),
34             Data::Union(un) => un.fields(),
35         }
36     }
37 
variants(&self) -> Vec<Vec<(&Visibility, TokenStream, &Type)>>38     fn variants(&self) -> Vec<Vec<(&Visibility, TokenStream, &Type)>> {
39         match self {
40             Data::Struct(strc) => strc.variants(),
41             Data::Enum(enm) => enm.variants(),
42             Data::Union(un) => un.variants(),
43         }
44     }
45 
tag(&self) -> Option<Ident>46     fn tag(&self) -> Option<Ident> {
47         match self {
48             Data::Struct(strc) => strc.tag(),
49             Data::Enum(enm) => enm.tag(),
50             Data::Union(un) => un.tag(),
51         }
52     }
53 }
54 
55 impl DataExt for DataStruct {
fields(&self) -> Vec<(&Visibility, TokenStream, &Type)>56     fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> {
57         map_fields(&self.fields)
58     }
59 
variants(&self) -> Vec<Vec<(&Visibility, TokenStream, &Type)>>60     fn variants(&self) -> Vec<Vec<(&Visibility, TokenStream, &Type)>> {
61         vec![self.fields()]
62     }
63 
tag(&self) -> Option<Ident>64     fn tag(&self) -> Option<Ident> {
65         None
66     }
67 }
68 
69 impl DataExt for DataEnum {
fields(&self) -> Vec<(&Visibility, TokenStream, &Type)>70     fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> {
71         map_fields(self.variants.iter().flat_map(|var| &var.fields))
72     }
73 
variants(&self) -> Vec<Vec<(&Visibility, TokenStream, &Type)>>74     fn variants(&self) -> Vec<Vec<(&Visibility, TokenStream, &Type)>> {
75         self.variants.iter().map(|var| map_fields(&var.fields)).collect()
76     }
77 
tag(&self) -> Option<Ident>78     fn tag(&self) -> Option<Ident> {
79         Some(Ident::new("___ZerocopyTag", Span::call_site()))
80     }
81 }
82 
83 impl DataExt for DataUnion {
fields(&self) -> Vec<(&Visibility, TokenStream, &Type)>84     fn fields(&self) -> Vec<(&Visibility, TokenStream, &Type)> {
85         map_fields(&self.fields.named)
86     }
87 
variants(&self) -> Vec<Vec<(&Visibility, TokenStream, &Type)>>88     fn variants(&self) -> Vec<Vec<(&Visibility, TokenStream, &Type)>> {
89         vec![self.fields()]
90     }
91 
tag(&self) -> Option<Ident>92     fn tag(&self) -> Option<Ident> {
93         None
94     }
95 }
96 
map_fields<'a>( fields: impl 'a + IntoIterator<Item = &'a Field>, ) -> Vec<(&'a Visibility, TokenStream, &'a Type)>97 fn map_fields<'a>(
98     fields: impl 'a + IntoIterator<Item = &'a Field>,
99 ) -> Vec<(&'a Visibility, TokenStream, &'a Type)> {
100     fields
101         .into_iter()
102         .enumerate()
103         .map(|(idx, f)| {
104             (
105                 &f.vis,
106                 f.ident
107                     .as_ref()
108                     .map(ToTokens::to_token_stream)
109                     .unwrap_or_else(|| Index::from(idx).to_token_stream()),
110                 &f.ty,
111             )
112         })
113         .collect()
114 }
115