spacetime_bindings_macro_input/
sats.rs1extern crate core;
2extern crate proc_macro;
3
4use proc_macro2::TokenStream;
5use quote::ToTokens;
6use syn::LitStr;
7
8use super::sym;
9use super::util::{check_duplicate, match_meta};
10
11pub struct SatsType<'a> {
12 pub ident: &'a syn::Ident,
13 pub generics: &'a syn::Generics,
14 pub name: LitStr,
15 pub krate: TokenStream,
16 #[allow(unused)]
18 pub original_attrs: &'a [syn::Attribute],
19 pub data: SatsTypeData<'a>,
20 pub is_repr_c: bool,
22}
23
24pub enum SatsTypeData<'a> {
25 Product(Vec<SatsField<'a>>),
26 Sum(Vec<SatsVariant<'a>>),
27}
28
29#[derive(Clone)]
30pub struct SatsField<'a> {
31 pub ident: Option<&'a syn::Ident>,
32 pub vis: &'a syn::Visibility,
33 pub name: Option<String>,
34 pub ty: &'a syn::Type,
35 pub original_attrs: &'a [syn::Attribute],
36}
37
38pub struct SatsVariant<'a> {
39 pub ident: &'a syn::Ident,
40 pub name: String,
41 pub ty: Option<&'a syn::Type>,
42 pub member: Option<syn::Member>,
43 #[allow(unused)]
45 pub original_attrs: &'a [syn::Attribute],
46}
47
48pub fn sats_type_from_derive(
49 input: &syn::DeriveInput,
50 crate_fallback: TokenStream,
51) -> syn::Result<SatsType<'_>> {
52 let data = match &input.data {
53 syn::Data::Struct(struc) => {
54 let fields = struc.fields.iter().map(|field| SatsField {
55 ident: field.ident.as_ref(),
56 vis: &field.vis,
57 name: field.ident.as_ref().map(syn::Ident::to_string),
58 ty: &field.ty,
59 original_attrs: &field.attrs,
60 });
61 SatsTypeData::Product(fields.collect())
62 }
63 syn::Data::Enum(enu) => {
64 let variants = enu.variants.iter().map(|var| {
65 let (member, ty) = variant_data(var)?.unzip();
66 Ok(SatsVariant {
67 ident: &var.ident,
68 name: var.ident.to_string(),
69 ty,
70 member,
71 original_attrs: &var.attrs,
72 })
73 });
74 SatsTypeData::Sum(variants.collect::<syn::Result<Vec<_>>>()?)
75 }
76 syn::Data::Union(u) => {
77 return Err(syn::Error::new(u.union_token.span, "unions not supported"));
78 }
79 };
80 extract_sats_type(
81 &input.ident,
82 &input.generics,
83 &input.attrs,
84 data,
85 crate_fallback,
86 )
87}
88
89fn is_repr_c(attrs: &[syn::Attribute]) -> bool {
90 let mut is_repr_c = false;
91 for attr in attrs.iter().filter(|a| a.path() == sym::repr) {
92 let _ = attr.parse_nested_meta(|meta| {
93 is_repr_c |= meta.path.is_ident("C");
94 Ok(())
95 });
96 }
97 is_repr_c
98}
99
100fn extract_sats_type<'a>(
101 ident: &'a syn::Ident,
102 generics: &'a syn::Generics,
103 attrs: &'a [syn::Attribute],
104 data: SatsTypeData<'a>,
105 crate_fallback: TokenStream,
106) -> syn::Result<SatsType<'a>> {
107 let mut name = None;
108 let mut krate = None;
109 for attr in attrs {
110 if attr.path() != sym::sats {
111 continue;
112 }
113 attr.parse_nested_meta(|meta| {
114 match_meta!(match meta {
115 sym::crate_ => {
116 check_duplicate(&krate, &meta)?;
117 let value = meta.value()?;
118 let v = value.call(syn::Path::parse_mod_style)?;
119 krate = Some(v.into_token_stream());
120 }
121 sym::name => {
122 check_duplicate(&name, &meta)?;
123 let value = meta.value()?;
124 let v = value.parse::<LitStr>()?;
125 name = Some(v);
126 }
127 });
128 Ok(())
129 })?;
130 }
131 let krate = krate.unwrap_or(crate_fallback);
132 let name = name.unwrap_or_else(|| crate::util::ident_to_litstr(ident));
133
134 let is_repr_c = is_repr_c(attrs);
135
136 Ok(SatsType {
137 ident,
138 generics,
139 name,
140 krate,
141 original_attrs: attrs,
142 data,
143 is_repr_c,
144 })
145}
146
147fn variant_data(variant: &syn::Variant) -> syn::Result<Option<(syn::Member, &syn::Type)>> {
148 let field = match &variant.fields {
149 syn::Fields::Named(f) if f.named.len() == 1 => &f.named[0],
150 syn::Fields::Named(_) => {
151 return Err(syn::Error::new_spanned(
152 &variant.fields,
153 "must be a unit variant or a newtype variant",
154 ));
155 }
156 syn::Fields::Unnamed(f) if f.unnamed.len() != 1 => {
157 return Err(syn::Error::new_spanned(
158 &variant.fields,
159 "must be a unit variant or a newtype variant",
160 ));
161 }
162 syn::Fields::Unnamed(f) => &f.unnamed[0],
163 syn::Fields::Unit => return Ok(None),
164 };
165 let member = field
166 .ident
167 .clone()
168 .map(Into::into)
169 .unwrap_or_else(|| syn::Member::from(0));
170 Ok(Some((member, &field.ty)))
171}