123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- use crate::Ctxt;
- use syn::{self, AngleBracketedGenericArguments, PathSegment};
- #[derive(Eq, PartialEq, Debug)]
- pub enum PrimitiveTy {
- Map(MapInfo),
- Vec,
- Opt,
- Other,
- }
- #[derive(Debug)]
- pub struct TyInfo<'a> {
- pub ident: &'a syn::Ident,
- pub ty: &'a syn::Type,
- pub primitive_ty: PrimitiveTy,
- pub bracket_ty_info: Box<Option<TyInfo<'a>>>,
- }
- #[derive(Debug, Eq, PartialEq)]
- pub struct MapInfo {
- pub key: String,
- pub value: String,
- }
- impl MapInfo {
- fn new(key: String, value: String) -> Self { MapInfo { key, value } }
- }
- impl<'a> TyInfo<'a> {
- #[allow(dead_code)]
- pub fn bracketed_ident(&'a self) -> &'a syn::Ident {
- match self.bracket_ty_info.as_ref() {
- Some(b_ty) => b_ty.ident,
- None => {
- panic!()
- },
- }
- }
- }
- pub fn parse_ty<'a>(ctxt: &Ctxt, ty: &'a syn::Type) -> Option<TyInfo<'a>> {
- // Type -> TypePath -> Path -> PathSegment -> PathArguments ->
- // AngleBracketedGenericArguments -> GenericArgument -> Type.
- if let syn::Type::Path(ref p) = ty {
- if p.path.segments.len() != 1 {
- return None;
- }
- let seg = match p.path.segments.last() {
- Some(seg) => seg,
- None => return None,
- };
- let is_option = seg.ident == "Option";
- return if let syn::PathArguments::AngleBracketed(ref bracketed) = seg.arguments {
- match seg.ident.to_string().as_ref() {
- "HashMap" => generate_hashmap_ty_info(ctxt, ty, seg, bracketed),
- "Vec" => generate_vec_ty_info(ctxt, seg, bracketed),
- "Option" => generate_option_ty_info(ty, seg),
- _ => {
- panic!("Unsupported ty")
- },
- }
- } else {
- return Some(TyInfo {
- ident: &seg.ident,
- ty,
- primitive_ty: PrimitiveTy::Other,
- bracket_ty_info: Box::new(None),
- });
- };
- }
- ctxt.error_spanned_by(ty, format!("Unsupported inner type, get inner type fail"));
- None
- }
- fn parse_bracketed(bracketed: &AngleBracketedGenericArguments) -> Vec<&syn::Type> {
- bracketed
- .args
- .iter()
- .flat_map(|arg| {
- if let syn::GenericArgument::Type(ref ty_in_bracket) = arg {
- Some(ty_in_bracket)
- } else {
- None
- }
- })
- .collect::<Vec<&syn::Type>>()
- }
- pub fn generate_hashmap_ty_info<'a>(
- ctxt: &Ctxt,
- ty: &'a syn::Type,
- path_segment: &'a PathSegment,
- bracketed: &'a AngleBracketedGenericArguments,
- ) -> Option<TyInfo<'a>> {
- // The args of map must greater than 2
- if bracketed.args.len() != 2 {
- return None;
- }
- let types = parse_bracketed(bracketed);
- let key = parse_ty(ctxt, types[0]).unwrap().ident.to_string();
- let value = parse_ty(ctxt, types[1]).unwrap().ident.to_string();
- let bracket_ty_info = Box::new(parse_ty(ctxt, &types[1]));
- return Some(TyInfo {
- ident: &path_segment.ident,
- ty,
- primitive_ty: PrimitiveTy::Map(MapInfo::new(key, value)),
- bracket_ty_info,
- });
- }
- fn generate_option_ty_info<'a>(
- ty: &'a syn::Type,
- path_segment: &'a PathSegment,
- ) -> Option<TyInfo<'a>> {
- assert_eq!(path_segment.ident.to_string(), "Option".to_string());
- return Some(TyInfo {
- ident: &path_segment.ident,
- ty,
- primitive_ty: PrimitiveTy::Opt,
- bracket_ty_info: Box::new(None),
- });
- }
- fn generate_vec_ty_info<'a>(
- ctxt: &Ctxt,
- path_segment: &'a PathSegment,
- bracketed: &'a AngleBracketedGenericArguments,
- ) -> Option<TyInfo<'a>> {
- if bracketed.args.len() != 1 {
- return None;
- }
- if let syn::GenericArgument::Type(ref bracketed_type) = bracketed.args.first().unwrap() {
- let bracketed_ty_info = Box::new(parse_ty(ctxt, &bracketed_type));
- return Some(TyInfo {
- ident: &path_segment.ident,
- ty: bracketed_type,
- primitive_ty: PrimitiveTy::Vec,
- bracket_ty_info: bracketed_ty_info,
- });
- }
- return None;
- }
|