cbindgen 0.1.6

A tool for generating C bindings to Rust code.
Documentation
use syn::*;

use bindgen::items::*;
use bindgen::library::*;

pub trait IterHelpers : Iterator {
    fn try_map<F, T, E>(&mut self, f: F) -> Result<Vec<T>, E>
        where F: FnMut(&Self::Item) -> Result<T, E>;
}
impl<I> IterHelpers for I where I: Iterator {
    fn try_map<F, T, E>(&mut self, mut f: F) -> Result<Vec<T>, E>
        where F: FnMut(&Self::Item) -> Result<T, E>
    {
        let mut out = Vec::new();
        while let Some(item) = self.next() {
            out.push(try!(f(&item)));
        }
        Ok(out)
    }
}

pub trait SynItemHelpers {
    fn has_attr(&self, target: MetaItem) -> bool;
    fn get_doc_attr(&self) -> String;

    fn is_no_mangle(&self) -> bool {
        self.has_attr(MetaItem::Word(Ident::new("no_mangle")))
    }
    fn is_repr_c(&self) -> bool {
        let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("C")))];
        self.has_attr(MetaItem::List(Ident::new("repr"), repr_args))
    }
    fn is_repr_u32(&self) -> bool {
        let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("u32")))];
        self.has_attr(MetaItem::List(Ident::new("repr"), repr_args))
    }
    fn is_repr_u16(&self) -> bool {
        let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("u16")))];
        self.has_attr(MetaItem::List(Ident::new("repr"), repr_args))
    }
    fn is_repr_u8(&self) -> bool {
        let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("u8")))];
        self.has_attr(MetaItem::List(Ident::new("repr"), repr_args))
    }
    fn get_repr(&self) -> Repr {
        if self.is_repr_c() {
            return Repr::C;
        }
        if self.is_repr_u32() {
            return Repr::U32;
        }
        if self.is_repr_u16() {
            return Repr::U16;
        }
        if self.is_repr_u8() {
            return Repr::U8;
        }
        Repr::None
    }
}
impl SynItemHelpers for Item {
    fn has_attr(&self, target: MetaItem) -> bool {
        return self.attrs
                   .iter()
                   .any(|ref attr| attr.style == AttrStyle::Outer && attr.value == target);
    }
    fn get_doc_attr(&self) -> String {
        let mut doc = String::new();
        for attr in &self.attrs {
            if attr.style == AttrStyle::Outer &&
               attr.is_sugared_doc {
                if let MetaItem::NameValue(_, Lit::Str(ref comment, _)) = attr.value {
                    doc.push_str(&comment);
                    doc.push('\n');
                }
            }
        }
        doc
    }
}
impl SynItemHelpers for ForeignItem {
    fn has_attr(&self, target: MetaItem) -> bool {
        return self.attrs
                   .iter()
                   .any(|ref attr| attr.style == AttrStyle::Outer && attr.value == target);
    }
    fn get_doc_attr(&self) -> String {
        let mut doc = String::new();
        for attr in &self.attrs {
            if attr.style == AttrStyle::Outer &&
               attr.is_sugared_doc {
                if let MetaItem::NameValue(_, Lit::Str(ref comment, _)) = attr.value {
                    doc.push_str(&comment);
                    doc.push('\n');
                }
            }
        }
        doc
    }
}

pub trait SynAbiHelpers {
    fn is_c(&self) -> bool;
}
impl SynAbiHelpers for Option<Abi> {
    fn is_c(&self) -> bool {
        self == &Some(Abi::Named(String::from("C")))
    }
}
impl SynAbiHelpers for Abi {
    fn is_c(&self) -> bool {
        self == &Abi::Named(String::from("C"))
    }
}

pub trait SynFnRetTyHelpers {
    fn as_type(&self) -> ConvertResult<Option<Type>>;
}
impl SynFnRetTyHelpers for FunctionRetTy {
    fn as_type(&self) -> ConvertResult<Option<Type>> {
        match self {
            &FunctionRetTy::Default => Ok(None),
            &FunctionRetTy::Ty(ref t) => Ok(Some(try!(Type::convert(t)))),
        }
    }
}

pub trait SynFnArgHelpers {
    fn as_ident_and_type(&self) -> ConvertResult<(String, Type)>;
}
impl SynFnArgHelpers for FnArg {
    fn as_ident_and_type(&self) -> ConvertResult<(String, Type)> {
        match self {
            &FnArg::Captured(Pat::Ident(_, ref ident, _), ref ty) => {
                Ok((ident.to_string(), try!(Type::convert(ty))))
            }
            _ => Err(format!("unexpected param type")),
        }
    }
}

pub trait SynFieldHelpers {
    fn as_ident_and_type(&self) -> ConvertResult<(String, Type)>;
}
impl SynFieldHelpers for Field {
    fn as_ident_and_type(&self) -> ConvertResult<(String, Type)> {
        let ident = try!(self.ident.as_ref().ok_or(format!("missing ident"))).clone();
        let converted_ty = try!(Type::convert(&self.ty));

        Ok((ident.to_string(), converted_ty))
    }
}

pub trait SynPathHelpers {
    fn convert_to_simple_single_segment(&self) -> ConvertResult<String>;
    fn convert_to_generic_single_segment(&self) -> ConvertResult<(String, Vec<Type>)>;
}
impl SynPathHelpers for Path {
    fn convert_to_simple_single_segment(&self) -> ConvertResult<String> {
        if self.segments.len() != 1 {
            return Err(format!("Path is not a single segment"));
        }

        match &self.segments[0].parameters {
            &PathParameters::AngleBracketed(ref d) => {
                if !d.lifetimes.is_empty() ||
                   !d.types.is_empty() ||
                   !d.bindings.is_empty() {
                    return Err(format!("Path contains generics, bindings, or lifetimes"));
                }
            }
            &PathParameters::Parenthesized(_) => {
                return Err(format!("Path contains parentheses"));
            }
        }

        let name = self.segments[0].ident.to_string();

        Ok(name)
    }

    fn convert_to_generic_single_segment(&self) -> ConvertResult<(String, Vec<Type>)> {
        if self.segments.len() != 1 {
            return Err(format!("Path is not a single segment"));
        }

        let generics = match &self.segments[0].parameters {
            &PathParameters::AngleBracketed(ref d) => {
                if !d.lifetimes.is_empty() ||
                   !d.bindings.is_empty() {
                    return Err(format!("Generic parameter contains bindings, or lifetimes"));
                }

                let mut generics = Vec::new();
                for ty in &d.types {
                    generics.push(try!(Type::convert(ty)));
                }
                generics
            }
            &PathParameters::Parenthesized(_) => {
                return Err(format!("Path contains parentheses"));
            }
        };

        let name = self.segments[0].ident.to_string();

        Ok((name, generics))
    }
}