typhoon-syn 0.3.0

Syntax tree utilities and helpers for macro processing
Documentation
use syn::{Expr, ExprLit, Ident, Lit, Path, ReturnType, Type, TypePath};

pub trait PathHelper {
    fn get_element_with_inner(&self) -> Option<(Ident, Option<Type>, Option<usize>)>;
}

impl PathHelper for ReturnType {
    fn get_element_with_inner(&self) -> Option<(Ident, Option<Type>, Option<usize>)> {
        match self {
            ReturnType::Default => None,
            ReturnType::Type(_, boxed_type) => match boxed_type.as_ref() {
                Type::Path(ty_path) => ty_path.get_element_with_inner(),
                _ => None,
            },
        }
    }
}

impl PathHelper for TypePath {
    fn get_element_with_inner(&self) -> Option<(Ident, Option<Type>, Option<usize>)> {
        self.path.get_element_with_inner()
    }
}

impl PathHelper for Path {
    fn get_element_with_inner(&self) -> Option<(Ident, Option<Type>, Option<usize>)> {
        let seg = self.segments.last()?;
        let (inner_type, inner_const_size) = extract_generic_arguments(&seg.arguments);

        Some((seg.ident.clone(), inner_type, inner_const_size))
    }
}

fn extract_generic_arguments(args: &syn::PathArguments) -> (Option<Type>, Option<usize>) {
    let mut inner_type = None;
    let mut inner_const_size = None;

    if let syn::PathArguments::AngleBracketed(angle_args) = args {
        for arg in &angle_args.args {
            match arg {
                syn::GenericArgument::Type(ty) if inner_type.is_none() => {
                    inner_type = Some(ty.clone());
                }
                syn::GenericArgument::Const(Expr::Lit(ExprLit {
                    lit: Lit::Int(lit), ..
                })) if inner_const_size.is_none() => {
                    if let Ok(val) = lit.base10_parse() {
                        inner_const_size = Some(val);
                    }
                }
                _ => continue,
            }
        }
    }

    (inner_type, inner_const_size)
}