use ffi::prelude::LLVMTypeRef;
use ffi::{core, target, LLVMTypeKind};
use libc::{c_int, c_uint};
use compile::Compile;
use context::{Context, GetContext};
use target::TargetData;
use util::{self, CastFrom};
use std::{fmt, mem};
use std::iter::Iterator;
use std::ops::Deref;
pub struct Type;
native_ref!(&Type = LLVMTypeRef);
impl Type {
#[inline(always)]
pub fn get<'a, T>(context:&'a Context) -> &'a Type where T:Compile<'a> {
T::get_type(context)
}
pub fn new_function<'a>(ret: &'a Type, args: &[&'a Type]) -> &'a FunctionType {
unsafe { core::LLVMFunctionType(ret.into(), args.as_ptr() as *mut LLVMTypeRef, args.len() as c_uint, 0) }.into()
}
pub fn new_array<'a>(element: &'a Type, length: usize) -> &'a Type {
unsafe { core::LLVMArrayType(element.into(), length as c_uint) }.into()
}
pub fn new_vector<'a>(element: &'a Type, length: usize) -> &'a Type {
unsafe { core::LLVMVectorType(element.into(), length as c_uint) }.into()
}
pub fn new_pointer<'a>(elem: &'a Type) -> &'a Type {
unsafe { core::LLVMPointerType(elem.into(), 0 as c_uint) }.into()
}
pub fn new_struct<'a>(elems: &[&'a Type], packed: bool) -> &'a Type {
unsafe { core::LLVMStructType(elems.as_ptr() as *mut LLVMTypeRef, elems.len() as c_uint, packed as c_int) }.into()
}
pub fn is_sized(&self) -> bool {
unsafe { core::LLVMTypeIsSized(self.into()) != 0 }
}
pub fn is_function(&self) -> bool {
let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
kind as c_uint == LLVMTypeKind::LLVMFunctionTypeKind as c_uint
}
pub fn is_struct(&self) -> bool {
let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
kind as c_uint == LLVMTypeKind::LLVMStructTypeKind as c_uint
}
pub fn is_void(&self) -> bool {
let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
kind as c_uint == LLVMTypeKind::LLVMVoidTypeKind as c_uint
}
pub fn is_pointer(&self) -> bool {
let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
kind as c_uint == LLVMTypeKind::LLVMPointerTypeKind as c_uint
}
pub fn is_integer(&self) -> bool {
let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
kind as c_uint == LLVMTypeKind::LLVMIntegerTypeKind as c_uint
}
pub fn is_float(&self) -> bool {
let kind = unsafe { core::LLVMGetTypeKind(self.into()) } as c_uint;
kind == LLVMTypeKind::LLVMHalfTypeKind as c_uint ||
kind == LLVMTypeKind::LLVMFloatTypeKind as c_uint ||
kind == LLVMTypeKind::LLVMDoubleTypeKind as c_uint
}
pub fn get_size(&self, target: &TargetData) -> usize {
unsafe { target::LLVMABISizeOfType(target.into(), self.into()) as usize }
}
pub fn get_element(&self) -> Option<&Type> {
unsafe { mem::transmute(core::LLVMGetElementType(self.into())) }
}
}
get_context!(Type, LLVMGetTypeContext);
to_str!(Type, LLVMPrintTypeToString);
pub struct StructType;
native_ref!(&StructType = LLVMTypeRef);
impl StructType {
pub fn new<'a>(context: &'a Context, fields: &[&'a Type], packed: bool) -> &'a StructType {
unsafe { core::LLVMStructTypeInContext(context.into(), fields.as_ptr() as *mut LLVMTypeRef, fields.len() as c_uint, packed as c_int) }.into()
}
pub fn new_named<'a>(context: &'a Context, name: &str, fields: &[&'a Type], packed: bool) -> &'a StructType {
util::with_cstr(name, |name| unsafe {
let ty = core::LLVMStructCreateNamed(context.into(), name);
core::LLVMStructSetBody(ty, fields.as_ptr() as *mut LLVMTypeRef, fields.len() as c_uint, packed as c_int);
ty.into()
})
}
pub fn get_elements(&self) -> Vec<Type> {
unsafe {
let size = core::LLVMCountStructElementTypes(self.into());
let mut els:Vec<_> = (0..size).map(|_| mem::uninitialized()).collect();
core::LLVMGetStructElementTypes(self.into(), els.as_mut_ptr() as *mut LLVMTypeRef);
els
}
}
}
impl CastFrom for StructType {
type From = Type;
fn cast(ty: &Type) -> Option<&StructType> {
unsafe {
let kind = core::LLVMGetTypeKind(ty.into());
if kind as c_uint == LLVMTypeKind::LLVMStructTypeKind as c_uint {
mem::transmute(ty)
} else {
None
}
}
}
}
deref!(StructType, Type);
get_context!(StructType, LLVMGetTypeContext);
to_str!(StructType, LLVMPrintTypeToString);
pub struct FunctionType;
native_ref!(&FunctionType = LLVMTypeRef);
deref!(FunctionType, Type);
impl CastFrom for FunctionType {
type From = Type;
fn cast(mut ty: &Type) -> Option<&FunctionType> {
unsafe {
use libc::c_uint;
while let Some(elem) = ty.get_element() {
ty = elem;
}
let kind = core::LLVMGetTypeKind(ty.into());
if kind as c_uint == LLVMTypeKind::LLVMFunctionTypeKind as c_uint {
mem::transmute(ty)
} else {
None
}
}
}
}
impl FunctionType {
pub fn num_params(&self) -> usize {
unsafe { core::LLVMCountParamTypes(self.into()) as usize }
}
pub fn get_params(&self) -> Vec<&Type> {
unsafe {
let count = core::LLVMCountParamTypes(self.into());
let mut types:Vec<_> = (0..count).map(|_| mem::uninitialized()).collect();
core::LLVMGetParamTypes(self.into(), types.as_mut_ptr() as *mut LLVMTypeRef);
types
}
}
pub fn get_return(&self) -> &Type {
unsafe { core::LLVMGetReturnType(self.into()).into() }
}
}
get_context!(FunctionType, LLVMGetTypeContext);
to_str!(FunctionType, LLVMPrintTypeToString);