milter-callback 0.2.4

Attribute macros for milter callback generation
Documentation
use syn::{FnArg, GenericArgument, PathArguments, ReturnType, Type};

pub fn is_result_return(return_type: &ReturnType) -> bool {
    match return_type {
        ReturnType::Type(_, ty) => match ty.as_ref() {
            Type::Path(ty) => match ty.path.segments.last() {
                // `ends_with` in order to accomodate (some) type aliasing.
                Some(segment) => segment.ident.to_string().ends_with("Result"),
                None => false,
            },
            _ => false,
        },
        _ => false,
    }
}

pub fn is_cstr_arg(fn_arg: &FnArg) -> bool {
    match fn_arg {
        FnArg::Typed(pat_type) => is_cstr(pat_type.ty.as_ref()),
        _ => false,
    }
}

pub fn is_cstrs_arg(fn_arg: &FnArg) -> bool {
    match fn_arg {
        FnArg::Typed(pat_type) => match pat_type.ty.as_ref() {
            Type::Path(ty) => match ty.path.segments.last() {
                Some(segment) => {
                    // `ends_with` in order to accomodate (some) type aliasing.
                    segment.ident.to_string().ends_with("Vec")
                        && match &segment.arguments {
                            PathArguments::AngleBracketed(generic_args) => {
                                let mut args = generic_args.args.iter();
                                match args.next() {
                                    Some(GenericArgument::Type(ty)) => {
                                        is_cstr(ty) && args.next().is_none()
                                    }
                                    _ => false,
                                }
                            }
                            _ => false,
                        }
                }
                None => false,
            },
            _ => false,
        },
        _ => false,
    }
}

fn is_cstr(ty: &Type) -> bool {
    match ty {
        Type::Reference(ty) => match ty.elem.as_ref() {
            Type::Path(ty) => match ty.path.segments.last() {
                Some(segment) => segment.ident == "CStr",
                None => false,
            },
            _ => false,
        },
        _ => false,
    }
}