ty_ext.rs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. use crate::Ctxt;
  2. use syn::{self, AngleBracketedGenericArguments, PathSegment};
  3. #[derive(Eq, PartialEq, Debug)]
  4. pub enum PrimitiveTy {
  5. Map(MapInfo),
  6. Vec,
  7. Opt,
  8. Other,
  9. }
  10. #[derive(Debug)]
  11. pub struct TyInfo<'a> {
  12. pub ident: &'a syn::Ident,
  13. pub ty: &'a syn::Type,
  14. pub primitive_ty: PrimitiveTy,
  15. pub bracket_ty_info: Box<Option<TyInfo<'a>>>,
  16. }
  17. #[derive(Debug, Eq, PartialEq)]
  18. pub struct MapInfo {
  19. pub key: String,
  20. pub value: String,
  21. }
  22. impl MapInfo {
  23. fn new(key: String, value: String) -> Self { MapInfo { key, value } }
  24. }
  25. impl<'a> TyInfo<'a> {
  26. #[allow(dead_code)]
  27. pub fn bracketed_ident(&'a self) -> &'a syn::Ident {
  28. match self.bracket_ty_info.as_ref() {
  29. Some(b_ty) => b_ty.ident,
  30. None => {
  31. panic!()
  32. },
  33. }
  34. }
  35. }
  36. pub fn parse_ty<'a>(ctxt: &Ctxt, ty: &'a syn::Type) -> Option<TyInfo<'a>> {
  37. // Type -> TypePath -> Path -> PathSegment -> PathArguments ->
  38. // AngleBracketedGenericArguments -> GenericArgument -> Type.
  39. if let syn::Type::Path(ref p) = ty {
  40. if p.path.segments.len() != 1 {
  41. return None;
  42. }
  43. let seg = match p.path.segments.last() {
  44. Some(seg) => seg,
  45. None => return None,
  46. };
  47. let is_option = seg.ident == "Option";
  48. return if let syn::PathArguments::AngleBracketed(ref bracketed) = seg.arguments {
  49. match seg.ident.to_string().as_ref() {
  50. "HashMap" => generate_hashmap_ty_info(ctxt, ty, seg, bracketed),
  51. "Vec" => generate_vec_ty_info(ctxt, seg, bracketed),
  52. "Option" => generate_option_ty_info(ty, seg),
  53. _ => {
  54. panic!("Unsupported ty")
  55. },
  56. }
  57. } else {
  58. return Some(TyInfo {
  59. ident: &seg.ident,
  60. ty,
  61. primitive_ty: PrimitiveTy::Other,
  62. bracket_ty_info: Box::new(None),
  63. });
  64. };
  65. }
  66. ctxt.error_spanned_by(ty, format!("Unsupported inner type, get inner type fail"));
  67. None
  68. }
  69. fn parse_bracketed(bracketed: &AngleBracketedGenericArguments) -> Vec<&syn::Type> {
  70. bracketed
  71. .args
  72. .iter()
  73. .flat_map(|arg| {
  74. if let syn::GenericArgument::Type(ref ty_in_bracket) = arg {
  75. Some(ty_in_bracket)
  76. } else {
  77. None
  78. }
  79. })
  80. .collect::<Vec<&syn::Type>>()
  81. }
  82. pub fn generate_hashmap_ty_info<'a>(
  83. ctxt: &Ctxt,
  84. ty: &'a syn::Type,
  85. path_segment: &'a PathSegment,
  86. bracketed: &'a AngleBracketedGenericArguments,
  87. ) -> Option<TyInfo<'a>> {
  88. // The args of map must greater than 2
  89. if bracketed.args.len() != 2 {
  90. return None;
  91. }
  92. let types = parse_bracketed(bracketed);
  93. let key = parse_ty(ctxt, types[0]).unwrap().ident.to_string();
  94. let value = parse_ty(ctxt, types[1]).unwrap().ident.to_string();
  95. let bracket_ty_info = Box::new(parse_ty(ctxt, &types[1]));
  96. return Some(TyInfo {
  97. ident: &path_segment.ident,
  98. ty,
  99. primitive_ty: PrimitiveTy::Map(MapInfo::new(key, value)),
  100. bracket_ty_info,
  101. });
  102. }
  103. fn generate_option_ty_info<'a>(
  104. ty: &'a syn::Type,
  105. path_segment: &'a PathSegment,
  106. ) -> Option<TyInfo<'a>> {
  107. assert_eq!(path_segment.ident.to_string(), "Option".to_string());
  108. return Some(TyInfo {
  109. ident: &path_segment.ident,
  110. ty,
  111. primitive_ty: PrimitiveTy::Opt,
  112. bracket_ty_info: Box::new(None),
  113. });
  114. }
  115. fn generate_vec_ty_info<'a>(
  116. ctxt: &Ctxt,
  117. path_segment: &'a PathSegment,
  118. bracketed: &'a AngleBracketedGenericArguments,
  119. ) -> Option<TyInfo<'a>> {
  120. if bracketed.args.len() != 1 {
  121. return None;
  122. }
  123. if let syn::GenericArgument::Type(ref bracketed_type) = bracketed.args.first().unwrap() {
  124. let bracketed_ty_info = Box::new(parse_ty(ctxt, &bracketed_type));
  125. return Some(TyInfo {
  126. ident: &path_segment.ident,
  127. ty: bracketed_type,
  128. primitive_ty: PrimitiveTy::Vec,
  129. bracket_ty_info: bracketed_ty_info,
  130. });
  131. }
  132. return None;
  133. }