ast.rs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #![allow(clippy::all)]
  2. #![allow(unused_attributes)]
  3. #![allow(unused_assignments)]
  4. use crate::{attr, ty_ext::*, AttrsContainer, Ctxt};
  5. use syn::{self, punctuated::Punctuated};
  6. pub struct ASTContainer<'a> {
  7. /// The struct or enum name (without generics).
  8. pub ident: syn::Ident,
  9. /// Attributes on the structure.
  10. pub attrs: AttrsContainer,
  11. /// The contents of the struct or enum.
  12. pub data: ASTData<'a>,
  13. }
  14. impl<'a> ASTContainer<'a> {
  15. pub fn from_ast(cx: &Ctxt, ast: &'a syn::DeriveInput) -> Option<ASTContainer<'a>> {
  16. let attrs = AttrsContainer::from_ast(cx, ast);
  17. // syn::DeriveInput
  18. // 1. syn::DataUnion
  19. // 2. syn::DataStruct
  20. // 3. syn::DataEnum
  21. let data = match &ast.data {
  22. syn::Data::Struct(data) => {
  23. // https://docs.rs/syn/1.0.48/syn/struct.DataStruct.html
  24. let (style, fields) = struct_from_ast(cx, &data.fields);
  25. ASTData::Struct(style, fields)
  26. }
  27. syn::Data::Union(_) => {
  28. cx.error_spanned_by(ast, "Does not support derive for unions");
  29. return None;
  30. }
  31. syn::Data::Enum(data) => {
  32. // https://docs.rs/syn/1.0.48/syn/struct.DataEnum.html
  33. ASTData::Enum(enum_from_ast(cx, &ast.ident, &data.variants, &ast.attrs))
  34. }
  35. };
  36. let ident = ast.ident.clone();
  37. let item = ASTContainer { ident, attrs, data };
  38. Some(item)
  39. }
  40. }
  41. pub enum ASTData<'a> {
  42. Struct(ASTStyle, Vec<ASTField<'a>>),
  43. Enum(Vec<ASTEnumVariant<'a>>),
  44. }
  45. impl<'a> ASTData<'a> {
  46. pub fn all_fields(&'a self) -> Box<dyn Iterator<Item = &'a ASTField<'a>> + 'a> {
  47. match self {
  48. ASTData::Enum(variants) => Box::new(variants.iter().flat_map(|variant| variant.fields.iter())),
  49. ASTData::Struct(_, fields) => Box::new(fields.iter()),
  50. }
  51. }
  52. pub fn all_variants(&'a self) -> Box<dyn Iterator<Item = &'a attr::ASTEnumAttrVariant> + 'a> {
  53. match self {
  54. ASTData::Enum(variants) => {
  55. let iter = variants.iter().map(|variant| &variant.attrs);
  56. Box::new(iter)
  57. }
  58. ASTData::Struct(_, fields) => {
  59. let iter = fields.iter().flat_map(|_| None);
  60. Box::new(iter)
  61. }
  62. }
  63. }
  64. pub fn all_idents(&'a self) -> Box<dyn Iterator<Item = &'a syn::Ident> + 'a> {
  65. match self {
  66. ASTData::Enum(variants) => Box::new(variants.iter().map(|v| &v.ident)),
  67. ASTData::Struct(_, fields) => {
  68. let iter = fields.iter().flat_map(|f| match &f.member {
  69. syn::Member::Named(ident) => Some(ident),
  70. _ => None,
  71. });
  72. Box::new(iter)
  73. }
  74. }
  75. }
  76. }
  77. /// A variant of an enum.
  78. pub struct ASTEnumVariant<'a> {
  79. pub ident: syn::Ident,
  80. pub attrs: attr::ASTEnumAttrVariant,
  81. pub style: ASTStyle,
  82. pub fields: Vec<ASTField<'a>>,
  83. pub original: &'a syn::Variant,
  84. }
  85. impl<'a> ASTEnumVariant<'a> {
  86. pub fn name(&self) -> String {
  87. self.ident.to_string()
  88. }
  89. }
  90. pub enum BracketCategory {
  91. Other,
  92. Opt,
  93. Vec,
  94. Map((String, String)),
  95. }
  96. pub struct ASTField<'a> {
  97. pub member: syn::Member,
  98. pub attrs: attr::ASTAttrField,
  99. pub ty: &'a syn::Type,
  100. pub original: &'a syn::Field,
  101. pub bracket_ty: Option<syn::Ident>,
  102. pub bracket_inner_ty: Option<syn::Ident>,
  103. pub bracket_category: Option<BracketCategory>,
  104. }
  105. impl<'a> ASTField<'a> {
  106. pub fn new(cx: &Ctxt, field: &'a syn::Field, index: usize) -> Result<Self, String> {
  107. let mut bracket_inner_ty = None;
  108. let mut bracket_ty = None;
  109. let mut bracket_category = Some(BracketCategory::Other);
  110. match parse_ty(cx, &field.ty) {
  111. Ok(Some(inner)) => {
  112. match inner.primitive_ty {
  113. PrimitiveTy::Map(map_info) => {
  114. bracket_category = Some(BracketCategory::Map((map_info.key.clone(), map_info.value)))
  115. }
  116. PrimitiveTy::Vec => {
  117. bracket_category = Some(BracketCategory::Vec);
  118. }
  119. PrimitiveTy::Opt => {
  120. bracket_category = Some(BracketCategory::Opt);
  121. }
  122. PrimitiveTy::Other => {
  123. bracket_category = Some(BracketCategory::Other);
  124. }
  125. }
  126. match *inner.bracket_ty_info {
  127. Some(bracketed_inner_ty) => {
  128. bracket_inner_ty = Some(bracketed_inner_ty.ident.clone());
  129. bracket_ty = Some(inner.ident.clone());
  130. }
  131. None => {
  132. bracket_ty = Some(inner.ident.clone());
  133. }
  134. }
  135. }
  136. Ok(None) => {
  137. let msg = format!("Fail to get the ty inner type: {:?}", field);
  138. return Err(msg);
  139. }
  140. Err(e) => {
  141. eprintln!("ASTField parser failed: {:?} with error: {}", field, e);
  142. return Err(e);
  143. }
  144. }
  145. Ok(ASTField {
  146. member: match &field.ident {
  147. Some(ident) => syn::Member::Named(ident.clone()),
  148. None => syn::Member::Unnamed(index.into()),
  149. },
  150. attrs: attr::ASTAttrField::from_ast(cx, index, field),
  151. ty: &field.ty,
  152. original: field,
  153. bracket_ty,
  154. bracket_inner_ty,
  155. bracket_category,
  156. })
  157. }
  158. pub fn ty_as_str(&self) -> String {
  159. match self.bracket_inner_ty {
  160. Some(ref ty) => ty.to_string(),
  161. None => self.bracket_ty.as_ref().unwrap().clone().to_string(),
  162. }
  163. }
  164. #[allow(dead_code)]
  165. pub fn name(&self) -> Option<syn::Ident> {
  166. if let syn::Member::Named(ident) = &self.member {
  167. Some(ident.clone())
  168. } else {
  169. None
  170. }
  171. }
  172. pub fn is_option(&self) -> bool {
  173. attr::is_option(self.ty)
  174. }
  175. }
  176. #[derive(Copy, Clone)]
  177. pub enum ASTStyle {
  178. Struct,
  179. /// Many unnamed fields.
  180. Tuple,
  181. /// One unnamed field.
  182. NewType,
  183. /// No fields.
  184. Unit,
  185. }
  186. pub fn struct_from_ast<'a>(cx: &Ctxt, fields: &'a syn::Fields) -> (ASTStyle, Vec<ASTField<'a>>) {
  187. match fields {
  188. syn::Fields::Named(fields) => (ASTStyle::Struct, fields_from_ast(cx, &fields.named)),
  189. syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
  190. (ASTStyle::NewType, fields_from_ast(cx, &fields.unnamed))
  191. }
  192. syn::Fields::Unnamed(fields) => (ASTStyle::Tuple, fields_from_ast(cx, &fields.unnamed)),
  193. syn::Fields::Unit => (ASTStyle::Unit, Vec::new()),
  194. }
  195. }
  196. pub fn enum_from_ast<'a>(
  197. cx: &Ctxt,
  198. ident: &syn::Ident,
  199. variants: &'a Punctuated<syn::Variant, Token![,]>,
  200. enum_attrs: &[syn::Attribute],
  201. ) -> Vec<ASTEnumVariant<'a>> {
  202. variants
  203. .iter()
  204. .flat_map(|variant| {
  205. let attrs = attr::ASTEnumAttrVariant::from_ast(cx, ident, variant, enum_attrs);
  206. let (style, fields) = struct_from_ast(cx, &variant.fields);
  207. Some(ASTEnumVariant {
  208. ident: variant.ident.clone(),
  209. attrs,
  210. style,
  211. fields,
  212. original: variant,
  213. })
  214. })
  215. .collect()
  216. }
  217. fn fields_from_ast<'a>(cx: &Ctxt, fields: &'a Punctuated<syn::Field, Token![,]>) -> Vec<ASTField<'a>> {
  218. fields
  219. .iter()
  220. .enumerate()
  221. .flat_map(|(index, field)| ASTField::new(cx, field, index).ok())
  222. .collect()
  223. }