use std::ptr;
use std::result;
use std::convert::TryFrom;
use sys::*;
use error::{Result, Error};
use api::{Value, JlValue, IntoSymbol, Array, Svec};
#[derive(Clone, Copy, Hash, PartialEq, Debug)]
pub enum VarargKind {
None,
Int,
Bound,
Unbound,
}
impl TryFrom<u32> for VarargKind {
type Error = ();
fn try_from(kind: u32) -> result::Result<VarargKind, ()> {
match kind {
0 => Ok(VarargKind::None),
1 => Ok(VarargKind::Int),
2 => Ok(VarargKind::Bound),
3 => Ok(VarargKind::Unbound),
_ => Err(()),
}
}
}
jlvalues! {
pub struct Type(jl_value_t);
pub struct Datatype(jl_datatype_t);
pub struct Union(jl_uniontype_t);
pub struct UnionAll(jl_unionall_t);
pub struct Tuple(jl_tupletype_t);
}
impl Type {
pub fn new_array<I>(&self, params: I) -> Result<Array>
where
I: IntoIterator<Item = Value>,
{
let mut paramv = vec![];
for p in params {
paramv.push(p.lock()?);
}
let dt = self.lock()?;
let array = unsafe { jl_alloc_array_1d(dt as *mut _, paramv.len()) };
jl_catch!();
for (i, p) in paramv.into_iter().enumerate() {
unsafe {
jl_arrayset(array, p, i);
}
}
jl_catch!();
Array::new(array)
}
pub fn apply_type<'a, I>(&self, params: I) -> Result<Type>
where
I: IntoIterator<Item=&'a Value>,
{
let mut paramv = vec![];
for p in params {
paramv.push(p.lock()?);
}
let nparam = paramv.len();
let paramv = paramv.as_mut_ptr();
let tc = self.lock()?;
let raw = unsafe { jl_apply_type(tc, paramv, nparam) };
jl_catch!();
Type::new(raw)
}
pub fn apply_type1(&self, p1: &Value) -> Result<Type> {
let tc = self.lock()?;
let p1 = p1.lock()?;
let raw = unsafe { jl_apply_type1(tc, p1) };
jl_catch!();
Type::new(raw)
}
pub fn apply_type2(&self, p1: &Value, p2: &Value) -> Result<Type> {
let tc = self.lock()?;
let p1 = p1.lock()?;
let p2 = p2.lock()?;
let raw = unsafe { jl_apply_type2(tc, p1, p2) };
jl_catch!();
Type::new(raw)
}
pub fn map<T, F>(&self, f: F) -> Result<T>
where
F: FnOnce(*mut jl_value_t) -> T,
{
self.lock().map(f)
}
pub fn map_or<T, F>(&self, f: F, optb: T) -> T
where
F: FnOnce(*mut jl_value_t) -> T,
{
self.lock().map(f).unwrap_or(optb)
}
pub fn map_or_else<T, F, O>(&self, f: F, op: O) -> T
where
F: FnOnce(*mut jl_value_t) -> T,
O: FnOnce(Error) -> T,
{
self.lock().map(f).unwrap_or_else(op)
}
pub fn unwrap_vararg(&self) -> Result<Type> {
let inner = self.lock()?;
let raw = unsafe { jl_unwrap_vararg(inner) };
Type::new(raw)
}
pub fn vararg_kind(&self) -> Result<VarargKind> {
let inner = self.lock()?;
let kind = unsafe { jl_vararg_kind(inner) };
Ok(VarargKind::try_from(kind).unwrap())
}
pub fn is_ok(&self) -> bool {
!self._inner.is_poisoned()
}
pub fn is_leaf_type(&self) -> bool {
self.map_or(|v| unsafe { jl_is_leaf_type(v as *mut _) != 0 }, false)
}
pub fn is_type(&self) -> bool {
self.map_or(|v| unsafe { jl_is_type(v as *mut _) }, false)
}
pub fn is_kind(&self) -> bool {
self.map_or(|v| unsafe { jl_is_kind(v as *mut _) }, false)
}
pub fn is_primitivetype(&self) -> bool {
self.map_or(|v| unsafe { jl_is_primitivetype(v) }, false)
}
pub fn is_structtype(&self) -> bool {
self.map_or(|v| unsafe { jl_is_structtype(v) }, false)
}
pub fn is_array_type(&self) -> bool {
self.map_or(|v| unsafe { jl_is_array_type(v) }, false)
}
pub fn is_abstracttype(&self) -> bool {
self.map_or(|v| unsafe { jl_is_abstracttype(v) }, false)
}
pub fn is_array(&self) -> bool {
self.map_or(|v| unsafe { jl_is_array(v) }, false)
}
pub fn is_cpointer_type(&self) -> bool {
self.map_or(|v| unsafe { jl_is_cpointer_type(v) }, false)
}
pub fn is_abstract_ref_type(&self) -> bool {
self.map_or(|v| unsafe { jl_is_abstract_ref_type(v) }, false)
}
pub fn is_tuple_type(&self) -> bool {
self.map_or(|v| unsafe { jl_is_tuple_type(v) }, false)
}
pub fn is_vecelement_type(&self) -> bool {
self.map_or(|v| unsafe { jl_is_vecelement_type(v) }, false)
}
pub fn is_type_type(&self) -> bool {
self.map_or(|v| unsafe { jl_is_type_type(v) }, false)
}
pub fn is_vararg_type(&self) -> bool {
self.map_or(|v| unsafe { jl_is_vararg_type(v) }, false)
}
}
impl Datatype {
pub fn new_struct<'a, I>(&self, params: I) -> Result<Value>
where
I: IntoIterator<Item=&'a Value>,
{
let mut paramv = vec![];
for p in params {
paramv.push(p.lock()?);
}
let nparam = paramv.len();
let paramv = paramv.as_mut_ptr();
let dt = self.lock()?;
let value = unsafe { jl_new_structv(dt, paramv, nparam as u32) };
jl_catch!();
Value::new(value)
}
pub fn new_bits<T: Into<Vec<u8>>>(&self, data: T) -> Result<Value> {
let data = data.into();
let bits = data.as_ptr();
let dt = self.lock()?;
let value = unsafe { jl_new_bits(dt as *mut _, bits as *mut _) };
jl_catch!();
Value::new(value)
}
pub fn any() -> Datatype {
unsafe { Datatype::new_unchecked(jl_any_type) }
}
pub fn number() -> Datatype {
unsafe { Datatype::new_unchecked(jl_number_type) }
}
pub fn signed() -> Datatype {
unsafe { Datatype::new_unchecked(jl_signed_type) }
}
pub fn abstract_float() -> Datatype {
unsafe { Datatype::new_unchecked(jl_floatingpoint_type) }
}
pub fn bool() -> Datatype {
unsafe { Datatype::new_unchecked(jl_bool_type) }
}
pub fn char() -> Datatype {
unsafe { Datatype::new_unchecked(jl_char_type) }
}
pub fn int8() -> Datatype {
unsafe { Datatype::new_unchecked(jl_int8_type) }
}
pub fn uint8() -> Datatype {
unsafe { Datatype::new_unchecked(jl_uint8_type) }
}
pub fn int16() -> Datatype {
unsafe { Datatype::new_unchecked(jl_int16_type) }
}
pub fn uint16() -> Datatype {
unsafe { Datatype::new_unchecked(jl_uint16_type) }
}
pub fn int32() -> Datatype {
unsafe { Datatype::new_unchecked(jl_int32_type) }
}
pub fn uint32() -> Datatype {
unsafe { Datatype::new_unchecked(jl_uint32_type) }
}
pub fn int64() -> Datatype {
unsafe { Datatype::new_unchecked(jl_int64_type) }
}
pub fn uint64() -> Datatype {
unsafe { Datatype::new_unchecked(jl_uint64_type) }
}
pub fn float16() -> Datatype {
unsafe { Datatype::new_unchecked(jl_float16_type) }
}
pub fn float32() -> Datatype {
unsafe { Datatype::new_unchecked(jl_float32_type) }
}
pub fn float64() -> Datatype {
unsafe { Datatype::new_unchecked(jl_float64_type) }
}
pub fn void() -> Datatype {
unsafe { Datatype::new_unchecked(jl_void_type) }
}
pub fn complex() -> Datatype {
unsafe { Datatype::new_unchecked(jl_complex_type as *mut _) }
}
pub fn void_pointer() -> Datatype {
unsafe { Datatype::new_unchecked(jl_voidpointer_type) }
}
pub fn pointer() -> Datatype {
unsafe { Datatype::new_unchecked(jl_pointer_type as *mut _) }
}
}
impl Default for Datatype {
fn default() -> Datatype {
Datatype::any()
}
}
impl Union {
pub fn union<'a, I>(ts: I) -> Result<Union>
where
I: IntoIterator<Item=&'a Datatype>,
{
let mut vec = vec![];
for t in ts {
vec.push(t.lock()?);
}
let n = vec.len();
let ts_ptr = vec.as_mut_ptr();
let raw = unsafe { jl_type_union(ts_ptr as *mut *mut _, n) };
jl_catch!();
Union::new(raw as *mut _)
}
pub fn intersection(a: &Union, b: &Union) -> Result<Union> {
let a = a.lock()?;
let b = b.lock()?;
let raw = unsafe { jl_type_intersection(a as *mut _, b as *mut _) };
jl_catch!();
Union::new(raw as *mut _)
}
pub fn has_empty_intersection(a: &Union, b: &Union) -> Result<bool> {
let a = a.lock()?;
let b = b.lock()?;
let p = unsafe { jl_has_empty_intersection(a as *mut _, b as *mut _) };
jl_catch!();
Ok(p != 0)
}
}
impl UnionAll {
pub fn instantiate(&self, p: &Value) -> Result<Type> {
let inner = self.lock()?;
let p = p.lock()?;
let raw = unsafe { jl_instantiate_unionall(inner, p) };
jl_catch!();
Type::new(raw)
}
}
impl Tuple {
pub fn apply(params: &Svec) -> Result<Tuple> {
let params = params.lock()?;
let raw = unsafe { jl_apply_tuple_type(params) };
jl_catch!();
Tuple::new(raw)
}
}
pub struct TypeBuilder {
name: *mut jl_sym_t,
supertype: *mut jl_datatype_t,
params: *mut jl_svec_t,
fnames: *mut jl_svec_t,
ftypes: *mut jl_svec_t,
nbits: usize,
abstrac: bool,
mutable: bool,
ninitialized: bool,
primitive: bool,
err: Option<Error>,
}
impl TypeBuilder {
pub fn new() -> TypeBuilder {
TypeBuilder {
name: ptr::null_mut(),
supertype: unsafe { jl_any_type },
params: unsafe { jl_emptysvec },
fnames: unsafe { jl_emptysvec },
ftypes: unsafe { jl_emptysvec },
nbits: 0,
abstrac: false,
mutable: false,
ninitialized: false,
primitive: false,
err: None,
}
}
pub fn err(&self) -> Option<&Error> {
self.err.as_ref()
}
pub fn is_err(&self) -> bool {
self.err.is_some()
}
pub fn build(self) -> Result<Datatype> {
if let Some(err) = self.err {
return Err(err);
}
if self.primitive {
let raw = unsafe {
jl_new_primitivetype(self.name as *mut _, self.supertype, self.params, self.nbits)
};
jl_catch!();
Datatype::new(raw)
} else {
let raw = unsafe {
jl_new_datatype(
self.name,
self.supertype,
self.params,
self.fnames,
self.ftypes,
self.abstrac as i32,
self.mutable as i32,
self.ninitialized as i32,
)
};
jl_catch!();
Datatype::new(raw)
}
}
pub fn name<S: IntoSymbol>(mut self, name: S) -> TypeBuilder {
let name = name.into_symbol();
if let Err(err) = name {
self.err = Some(err);
return self;
}
let name = name.unwrap().into_inner();
self.name = match name {
Ok(name) => name,
Err(err) => {
self.err = Some(err);
return self;
}
};
self
}
pub fn supertype(mut self, supertype: &Datatype) -> TypeBuilder {
self.supertype = match supertype.lock() {
Ok(supertype) => supertype,
Err(err) => {
self.err = Some(err);
return self;
}
};
self
}
pub fn params(mut self, params: &Svec) -> TypeBuilder {
self.params = match params.lock() {
Ok(params) => params,
Err(err) => {
self.err = Some(err);
return self;
}
};
self
}
pub fn fnames(mut self, fnames: &Svec) -> TypeBuilder {
self.fnames = match fnames.lock() {
Ok(fnames) => fnames,
Err(err) => {
self.err = Some(err);
return self;
}
};
self
}
pub fn ftypes(mut self, ftypes: &Svec) -> TypeBuilder {
self.ftypes = match ftypes.lock() {
Ok(ftypes) => ftypes,
Err(err) => {
self.err = Some(err);
return self;
}
};
self
}
pub fn nbits(mut self, nbits: usize) -> TypeBuilder {
self.nbits = nbits;
self
}
pub fn abstrac(mut self, abstrac: bool) -> TypeBuilder {
self.abstrac = abstrac;
self
}
pub fn mutable(mut self, mutable: bool) -> TypeBuilder {
self.mutable = mutable;
self
}
pub fn ninitialized(mut self, ninitialized: bool) -> TypeBuilder {
self.ninitialized = ninitialized;
self
}
pub fn primitive(mut self, primitive: bool) -> TypeBuilder {
self.primitive = primitive;
self
}
}
impl Default for TypeBuilder {
fn default() -> TypeBuilder {
TypeBuilder::new()
}
}
#[macro_export]
macro_rules! jl_type {
{ type $name:ident = Bits<N> where N: $nbits:expr; } => {
jl_type! { type $name = Bits<N> where N: $nbits, Self : Datatype::any(); }
};
{ type $name:ident = Bits<N> where N: $nbits:expr, Self : $supertype:expr; } => {
TypeBuilder::new()
.primitive(true)
.name(stringify!($name))
.supertype(&$supertype)
.nbits($nbits)
.build()
};
{ trait $name:ident; } => {
jl_type! { type $name: Datatype::any(); }
};
{ trait $name:ident : $supertype:expr; } => {
TypeBuilder::new()
.abstrac(true)
.name(stringify!($name))
.supertype(&$supertype)
.build()
};
{ struct $name:ident; } => {
jl_type! { struct $name: Datatype::any(); }
};
{ struct $name:ident : $supertype:expr; } => {
TypeBuilder::new()
.name(stringify!($name))
.supertype(&$supertype)
.build()
};
{
struct $name:ident {
$(
$fname:ident : $ftype:expr
),*
}
} => {
jl_type! {
struct $name {
$(
$fname : $ftype,
)*
} : Datatype::any()
}
};
{
struct $name:ident {
$(
$fname:ident : $ftype:expr,
)*
} : $supertype:expr
} => {
{
use $crate::error::Result;
use $crate::api::{IntoSymbol, Datatype};
fn build() -> Result<Datatype> {
TypeBuilder::new()
.name(stringify!($name))
.supertype(&$supertype)
.fnames(&jlvec![
$(
Value::from_value(
stringify!($fname).into_symbol()?
)?
),*
]?)
.ftypes(&jlvec![
$( Value::from_value($ftype)? ),*
]?)
.build()
}
build()
}
};
{ mut struct $name:ident; } => {
jl_type! { mut struct $name: Datatype::any(); }
};
{ mut struct $name:ident : $supertype:expr; } => {
TypeBuilder::new()
.mutable(true)
.name(stringify!($name))
.supertype(&$supertype)
.build()
};
{
mut struct $name:ident {
$(
$fname:ident : $ftype:expr,
)*
}
} => {
jl_type! {
mut struct $name {
$(
$fname : $ftype,
)*
} : Datatype::any()
}
};
{
mut struct $name:ident {
$(
$fname:ident : $ftype:expr,
)*
} : $supertype:expr
} => {
{
use $crate::error::Result;
use $crate::api::{IntoSymbol, Datatype};
fn build() -> Result<Datatype> {
TypeBuilder::new()
.mutable(true)
.name(stringify!($name))
.supertype(&$supertype)
.fnames(&jlvec![
$(
Value::from_value(
stringify!($fname).into_symbol()?
)?
),*
]?)
.ftypes(&jlvec![
$( Value::from_value($ftype)? ),*
]?)
.build()
}
build()
}
};
}