dustr 0.1.2

Generate dart code based on a rust ffishim
Documentation
use ::syn::*;
use crate::types::Behavior;

pub fn is_same_id(path: &Path, id: &str) -> bool {
    id == &path.segments.last().expect("always >1 segments").ident.to_string()
}

pub fn arg_ty(arg: &FnArg) -> &Type {
    match arg {
        FnArg::Receiver(_) => panic!("functions with 'self' not supported"),
        FnArg::Typed(pat) => pat.ty.as_ref(),
    }
}

pub fn arg_ident(arg: &FnArg) -> &Ident {
    match arg {
        FnArg::Receiver(_) => panic!("functions with 'self' not supported"),
        FnArg::Typed(pat) => match pat.pat.as_ref() {
            ::syn::Pat::Ident(pati) => &pati.ident,
            _ => panic!("non-ident arg patterns not supported"),
        },
    }
}

pub fn ret_ty(ifn: &ItemFn) -> Type {
    match &ifn.sig.output {
        ::syn::ReturnType::Default => parse_quote! {
            Result<(), ::ffishim::library::Error>
        },
        ::syn::ReturnType::Type(_, ty) => if crate::types::BehaviorResult.is(ty.as_ref()) {
            *ty.clone()
        } else {
            parse_quote! { Result<#ty, ::ffishim::library::Error> }
        },
    }
}

pub fn subtype(ty: Type) -> Type {
    let path = if let Type::Path(tp) = ty {
        tp.path
    } else {
        panic!("only normal type of kind typepath supported")
    };

    let segment = path.segments.into_iter().last().expect("always >0 elements in type path");

    let mut args = match segment.arguments {
        PathArguments::AngleBracketed(arguments) => arguments.args.into_iter(),
        PathArguments::None => panic!("expecting subtype"),
        _ => panic!("only bracketed arguments are supported"),
    };

    match args.next().expect("expecting subtype") {
        GenericArgument::Type(ty) => ty,
        _ => panic!("only the type arguments are supported"),
    }
}

pub fn type_name_from_path(ty: &Type) -> String {
    let path = if let Type::Path(tp) = &ty {
        &tp.path
    } else {
        panic!("only normal type of kind typepath supported")
    };

    path.segments.last().expect(">0 elements").ident.to_string()
}

pub fn name_of_field(idx: u32, ident: &Option<::syn::Ident>) -> String {
    if let Some(ident) = ident {
        ident.to_string()
    } else {
        alpha_idx(idx).to_owned()
    }
}

pub fn alpha_idx(idx: u32) -> &'static str {
    match idx {
        0 => "zero",
        1 => "one",
        2 => "two",
        3 => "three",
        4 => "four",
        5 => "five",
        6 => "six",
        7 => "seven",
        8 => "eight",
        9 => "nine",
        10 => "ten",
        11 => "eleven",
        12 => "twelve",
        13 => "thirteen",
        14 => "fourteen",
        15 => "fifteen",
        16 => "sixteen",
        17 => "seventeen",
        18 => "eighteen",
        19 => "nineteen",
        _ => panic!("does not support more than 20 tuple struct fields"),
    }
}

pub fn concat_idents(left: &::syn::Ident, right: &::syn::Ident) -> ::syn::Ident {
    new_ident(&format!("{}{}", left, right))
}

pub fn new_ident(src: &str) -> ::syn::Ident {
    ::syn::Ident::new(src, ::proc_macro2::Span::call_site())
}

pub fn tostring_if_some<T: ::std::fmt::Display>(val: &Option<T>) -> String {
    if let Some(val) = val {
        val.to_string()
    } else {
        "".to_owned()
    }
}