hllvm-sys 0.1.2

FFI wrapper around the LLVM C++ library
#![allow(improper_ctypes)]

pub use self::ir::*;
pub use self::target::*;
pub use self::support::*;

pub mod ir;
pub mod target;
pub mod support;

extern crate libc;
#[macro_use]
extern crate cpp;

// Required to link LLVM
extern crate ncurses;
// Required to link LLVM
#[link(name = "ffi")] extern { }

#[cfg(test)]
pub mod test_support;

macro_rules! define_borrowed_type {
    ($name:ident, $opaque_name:ident) => {
        pub enum $opaque_name { }
        pub type $name = *mut $opaque_name;
    }
}

/// We don't know the sizes of many LLVM types, and they can change.
///
/// To work around this, we box up values from C++ and deal with the boxed
/// pointers in Rust, and then dereference to get back to the inner value in C++ again.
macro_rules! define_boxed_type {
    ($name:ident, $opaque_name:ident) => {
        #[derive(Clone)]
        pub enum $opaque_name { }
        pub type $name = CppBox<$opaque_name>;
    }
}

define_borrowed_type!(ContextRef, OpaqueContext);
define_borrowed_type!(TypeRef, OpaqueType);
define_borrowed_type!(ValueRef, OpaqueValue);
define_borrowed_type!(TargetRef, OpaqueTarget);

define_borrowed_type!(TargetMachineRef, OpaqueTargetMachine);
define_borrowed_type!(PassManagerRef, OpaquePassManager);
define_borrowed_type!(RawPWriteStreamRef, OpaqueRawPWriteStream);

define_boxed_type!(AttributeRef, OpaqueAttribute);

/// A boxed value, allocated from C++.
/// We own the value and free it ourselves.
#[repr(C, packed)]
pub struct CppBox<T>
{
    ptr: *mut T,
}

impl<T> Drop for CppBox<T> {
    fn drop(&mut self) {
        unsafe { libc::free(self.ptr as *mut libc::c_void) }
    }
}

// We don't allow copying because that could lead to double-frees.
impl<T: Clone> Clone for CppBox<T> {
    fn clone(&self) -> Self {
        use std::mem::size_of;
        use std::ptr;

        unsafe {
            let new_ptr = libc::malloc(size_of::<T>()) as *mut T;
            ptr::copy(self.ptr, new_ptr, size_of::<T>());

            CppBox { ptr: new_ptr }
        }
    }
}

#[cfg(test)]
mod test
{
    #[test]
    fn test_slice_repr_hasnt_changed() {
        let ptr = 0xDEADBEEF as *const u8;
        let len = 0xCAFEBABE;

        unsafe {
            let slice = ::std::slice::from_raw_parts(ptr, len);
            assert_eq!(slice.as_ptr(), ptr);
            assert_eq!(slice.len(), len);

            #[repr(C)]
            struct Slice { ptr: *const u8, len: usize }
            let slice: Slice = ::std::mem::transmute(slice);
            assert_eq!(slice.ptr, ptr);
            assert_eq!(slice.len, len);
        }
    }
}