use std::fmt;
use std::mem;
use std::ptr;
use libc;
use low;
use super::util::Unique;
type Type_ = *mut low::ffi_type;
type TypeArray_ = *mut Type_;
type Owned<T> = T;
pub struct Type(Unique<low::ffi_type>);
pub struct TypeArray(Unique<*mut low::ffi_type>);
impl fmt::Debug for Type {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_fmt(format_args!("Type({:?})", *self.0))
}
}
impl fmt::Debug for TypeArray {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_fmt(format_args!("TypeArray({:?})", *self.0))
}
}
unsafe fn ffi_type_array_len(mut array: TypeArray_) -> usize {
let mut count = 0;
while !(*array).is_null() {
count += 1;
array = array.offset(1);
}
count
}
unsafe fn ffi_type_array_create_empty(len: usize) -> Owned<TypeArray_> {
let array = libc::malloc((len + 1) * mem::size_of::<Type_>())
as TypeArray_;
assert!(!array.is_null(),
"ffi_type_array_create_empty: out of memory");
*array.offset(len as isize) = ptr::null_mut::<low::ffi_type>() as Type_;
array
}
unsafe fn ffi_type_array_create<I>(elements: I) -> Owned<TypeArray_>
where I: ExactSizeIterator<Item=Type>
{
let size = elements.len();
let new = ffi_type_array_create_empty(size);
for (i, element) in elements.enumerate() {
*new.offset(i as isize) = *element.0;
}
new
}
unsafe fn ffi_type_struct_create_raw(elements: Owned<TypeArray_>)
-> Owned<Type_>
{
let new = libc::malloc(mem::size_of::<low::ffi_type>()) as Type_;
assert!(!new.is_null(),
"ffi_type_struct_create_raw: out of memory");
(*new).size = 0;
(*new).alignment = 0;
(*new).type_ = low::type_tag::STRUCT;
(*new).elements = elements;
new
}
unsafe fn ffi_type_struct_create<I>(elements: I) -> Owned<Type_>
where I: ExactSizeIterator<Item=Type>
{
ffi_type_struct_create_raw(ffi_type_array_create(elements))
}
unsafe fn ffi_type_array_clone(old: TypeArray_) -> Owned<TypeArray_> {
let size = ffi_type_array_len(old);
let new = ffi_type_array_create_empty(size);
for i in 0 .. size {
*new.offset(i as isize) = ffi_type_clone(*old.offset(i as isize));
}
new
}
unsafe fn ffi_type_clone(old: Type_) -> Owned<Type_> {
if (*old).type_ == low::type_tag::STRUCT {
ffi_type_struct_create_raw(ffi_type_array_clone((*old).elements))
} else {
old
}
}
unsafe fn ffi_type_array_destroy(victim: Owned<TypeArray_>) {
let mut current = victim;
while !(*current).is_null() {
ffi_type_destroy(*current);
current = current.offset(1);
}
libc::free(victim as *mut libc::c_void);
}
unsafe fn ffi_type_destroy(victim: Owned<Type_>) {
if (*victim).type_ == low::type_tag::STRUCT {
ffi_type_array_destroy((*victim).elements);
libc::free(victim as *mut libc::c_void);
}
}
impl Drop for Type {
fn drop(&mut self) {
unsafe { ffi_type_destroy(*self.0) }
}
}
impl Drop for TypeArray {
fn drop(&mut self) {
unsafe { ffi_type_array_destroy(*self.0) }
}
}
impl Clone for Type {
fn clone(&self) -> Self {
Type(unsafe { Unique::new(ffi_type_clone(*self.0)) })
}
}
impl Clone for TypeArray {
fn clone(&self) -> Self {
TypeArray(unsafe {
Unique::new(ffi_type_array_clone(*self.0))
})
}
}
macro_rules! match_size_signed {
( $name:ident ) => {
match mem::size_of::<libc::$name>() {
1 => Self::i8(),
2 => Self::i16(),
4 => Self::i32(),
8 => Self::i64(),
_ => panic!("Strange size for C type"),
}
}
}
macro_rules! match_size_unsigned {
( $name:ident ) => {
match mem::size_of::<libc::$name>() {
1 => Self::u8(),
2 => Self::u16(),
4 => Self::u32(),
8 => Self::u64(),
_ => panic!("Strange size for C type"),
}
}
}
impl Type {
pub fn void() -> Self {
Type(unsafe { Unique::new(&mut low::types::void) })
}
pub fn u8() -> Self {
Type(unsafe { Unique::new(&mut low::types::uint8) })
}
pub fn i8() -> Self {
Type(unsafe { Unique::new(&mut low::types::sint8) })
}
pub fn u16() -> Self {
Type(unsafe { Unique::new(&mut low::types::uint16) })
}
pub fn i16() -> Self {
Type(unsafe { Unique::new(&mut low::types::sint16) })
}
pub fn u32() -> Self {
Type(unsafe { Unique::new(&mut low::types::uint32) })
}
pub fn i32() -> Self {
Type(unsafe { Unique::new(&mut low::types::sint32) })
}
pub fn u64() -> Self {
Type(unsafe { Unique::new(&mut low::types::uint64) })
}
pub fn i64() -> Self {
Type(unsafe { Unique::new(&mut low::types::sint64) })
}
#[cfg(target_pointer_width = "16")]
pub fn usize() -> Self {
Self::u16()
}
#[cfg(target_pointer_width = "16")]
pub fn isize() -> Self {
Self::i16()
}
#[cfg(target_pointer_width = "32")]
pub fn usize() -> Self {
Self::u32()
}
#[cfg(target_pointer_width = "32")]
pub fn isize() -> Self {
Self::i32()
}
#[cfg(target_pointer_width = "64")]
pub fn usize() -> Self {
Self::u64()
}
#[cfg(target_pointer_width = "64")]
pub fn isize() -> Self {
Self::i64()
}
pub fn c_schar() -> Self {
match_size_signed!(c_schar)
}
pub fn c_uchar() -> Self {
match_size_unsigned!(c_uchar)
}
pub fn c_short() -> Self {
match_size_signed!(c_short)
}
pub fn c_ushort() -> Self {
match_size_unsigned!(c_ushort)
}
pub fn c_int() -> Self {
match_size_signed!(c_int)
}
pub fn c_uint() -> Self {
match_size_unsigned!(c_uint)
}
pub fn c_long() -> Self {
match_size_signed!(c_long)
}
pub fn c_ulong() -> Self {
match_size_unsigned!(c_ulong)
}
pub fn c_longlong() -> Self {
match_size_signed!(c_longlong)
}
pub fn c_ulonglong() -> Self {
match_size_unsigned!(c_ulonglong)
}
pub fn f32() -> Self {
Type(unsafe { Unique::new(&mut low::types::float) })
}
pub fn f64() -> Self {
Type(unsafe { Unique::new(&mut low::types::double) })
}
pub fn pointer() -> Self {
Type(unsafe { Unique::new(&mut low::types::pointer) })
}
pub fn longdouble() -> Self {
Type(unsafe { Unique::new(&mut low::types::longdouble) })
}
#[cfg(feature = "complex")]
pub fn c32() -> Self {
Type(unsafe { Unique::new(&mut low::types::complex_float) })
}
#[cfg(feature = "complex")]
pub fn c64() -> Self {
Type(unsafe { Unique::new(&mut low::types::complex_double) })
}
#[cfg(feature = "complex")]
pub fn complex_longdouble() -> Self {
Type(unsafe { Unique::new(&mut low::types::complex_longdouble) })
}
pub fn structure<I>(fields: I) -> Self
where I: IntoIterator<Item=Type>,
I::IntoIter: ExactSizeIterator<Item=Type>
{
Type(unsafe {
Unique::new(ffi_type_struct_create(fields.into_iter()))
})
}
pub fn as_raw_ptr(&self) -> *mut low::ffi_type {
*self.0
}
}
impl TypeArray {
pub fn new<I>(elements: I) -> Self
where I: IntoIterator<Item=Type>,
I::IntoIter: ExactSizeIterator<Item=Type>
{
TypeArray(unsafe {
Unique::new(ffi_type_array_create(elements.into_iter()))
})
}
pub fn as_raw_ptr(&self) -> *mut *mut low::ffi_type {
*self.0
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn create_u64() {
Type::u64();
}
#[test]
fn clone_u64() {
Type::u64().clone().clone();
}
#[test]
fn create_struct() {
Type::structure(vec![Type::i64(),
Type::i64(),
Type::u64()]);
}
#[test]
fn clone_struct() {
Type::structure(vec![Type::i64(),
Type::i64(),
Type::u64()]).clone().clone();
}
}