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