diesel_codegen 0.16.1

Custom derive and procedural macros for Diesel
Documentation
use quote::Tokens;
use syn::*;

use ast_builder::ty_ident;

pub fn struct_ty(name: Ident, generics: &Generics) -> Ty {
    let lifetimes = generics.lifetimes.iter().map(|lt| lt.lifetime.clone()).collect();
    let ty_params = generics.ty_params.iter()
        .map(|param| ty_ident(param.ident.clone()))
        .collect();
    let parameter_data = AngleBracketedParameterData {
        lifetimes: lifetimes,
        types: ty_params,
        bindings: Vec::new(),
    };
    let parameters = PathParameters::AngleBracketed(parameter_data);
    Ty::Path(None, Path {
        global: false,
        segments: vec![
            PathSegment {
                ident: name,
                parameters: parameters,
            },
        ],
    })
}

pub fn str_value_of_attr_with_name<'a>(
    attrs: &'a [Attribute],
    name: &str,
) -> Option<&'a str> {
    attr_with_name(attrs, name).map(|attr| str_value_of_attr(attr, name))
}

pub fn ident_value_of_attr_with_name<'a>(
    attrs: &'a [Attribute],
    name: &str,
) -> Option<&'a Ident> {
    list_value_of_attr_with_name(attrs, name).map(|idents| {
        if idents.len() != 1 {
            panic!(r#"`{}` must be in the form `#[{}(something)]`"#, name, name);
        }
        idents[0]
    })
}

pub fn list_value_of_attr_with_name<'a>(
    attrs: &'a [Attribute],
    name: &str,
) -> Option<Vec<&'a Ident>> {
    attr_with_name(attrs, name).map(|attr| list_value_of_attr(attr, name))
}

pub fn attr_with_name<'a>(
    attrs: &'a [Attribute],
    name: &str,
) -> Option<&'a Attribute> {
    attrs.into_iter().find(|attr| attr.name() == name)
}

fn str_value_of_attr<'a>(attr: &'a Attribute, name: &str) -> &'a str {
    str_value_of_meta_item(&attr.value, name)
}

pub fn str_value_of_meta_item<'a>(item: &'a MetaItem, name: &str) -> &'a str {
    match *item {
        MetaItem::NameValue(_, Lit::Str(ref value, _)) => &*value,
        _ => panic!(r#"`{}` must be in the form `#[{}="something"]`"#, name, name),
    }
}

fn list_value_of_attr<'a>(attr: &'a Attribute, name: &str) -> Vec<&'a Ident> {
    match attr.value {
        MetaItem::List(_, ref items) => {
            items.iter().map(|item| match *item {
                NestedMetaItem::MetaItem(MetaItem::Word(ref name)) => name,
                _ => panic!(r#"`{}` must be in the form `#[{}(something)]`"#, name, name),
            }).collect()
        }
        _ => panic!(r#"`{}` must be in the form `#[{}(something)]`"#, name, name),
    }
}

pub fn is_option_ty(ty: &Ty) -> bool {
    let option_ident = Ident::new("Option");
    match *ty {
        Ty::Path(_, ref path) => {
            path.segments.first()
                .map(|s| s.ident == option_ident)
                .unwrap_or(false)
        }
        _ => false,
    }
}

pub fn inner_of_option_ty(ty: &Ty) -> Option<&Ty> {
    use syn::PathParameters::AngleBracketed;

    if !is_option_ty(ty) {
        return None;
    }

    match *ty {
        Ty::Path(_, Path { ref segments, .. }) =>
            match segments[0].parameters {
                AngleBracketed(ref data) => data.types.first(),
                _ => None,
            },
        _ => None,
    }
}

pub fn get_options_from_input(name: &str, attrs: &[Attribute], on_bug: fn() -> !)
    -> Option<Vec<MetaItem>>
{
    let options = attrs.iter().find(|a| a.name() == name).map(|a| &a.value);
    match options {
        Some(&MetaItem::List(_, ref options)) => {
            Some(options.iter().map(|o| match *o {
                NestedMetaItem::MetaItem(ref m) => m.clone(),
                _ => on_bug(),
            }).collect())
        }
        Some(_) => on_bug(),
        None => None,
    }
}

pub fn get_option<'a>(
    options: &'a [MetaItem],
    option_name: &str,
    on_bug: fn() -> !,
) -> &'a str {
    get_optional_option(options, option_name)
        .unwrap_or_else(|| on_bug())
}

pub fn get_optional_option<'a>(
    options: &'a [MetaItem],
    option_name: &str,
) -> Option<&'a str> {
    options.iter().find(|a| a.name() == option_name)
        .map(|a| str_value_of_meta_item(a, option_name))
}

pub fn wrap_item_in_const(const_name: Ident, item: Tokens) -> Tokens {
    quote! {
        const #const_name: () = {
            extern crate diesel;
            #item
        };
    }
}