use core::alloc;
use core::bigarray;
use core::memory;
use core::mlvalues;
use core::mlvalues::empty_list;
use error::Error;
use tag::Tag;
use std::marker::PhantomData;
use std::mem;
use std::ptr;
use std::slice;
use value::{Size, Value};
pub struct Tuple(Value, Size);
impl From<Tuple> for Value {
fn from(t: Tuple) -> Value {
t.0
}
}
impl<R: AsRef<[Value]>> From<R> for Tuple {
fn from(t: R) -> Tuple {
let mut dst = Tuple::new(t.as_ref().len());
for (n, item) in t.as_ref().iter().enumerate() {
let _ = dst.set(n, item.clone());
}
dst
}
}
impl Tuple {
pub fn new(n: Size) -> Tuple {
unsafe {
let val = Value::new(alloc::caml_alloc_tuple(n));
Tuple(val, n)
}
}
pub fn len(&self) -> Size {
self.1
}
pub fn set(&mut self, i: Size, v: Value) -> Result<(), Error> {
if i < self.1 {
self.0.store_field(i, v);
Ok(())
} else {
Err(Error::OutOfBounds)
}
}
pub fn get(&self, i: Size) -> Result<Value, Error> {
if i < self.1 {
Ok(self.0.field(i))
} else {
Err(Error::OutOfBounds)
}
}
}
pub struct Array(Value);
impl From<Array> for Value {
fn from(t: Array) -> Value {
t.0
}
}
impl<R: AsRef<[Value]>> From<R> for Array {
fn from(t: R) -> Array {
let mut dst = Array::new(t.as_ref().len());
for (n, item) in t.as_ref().iter().enumerate() {
let _ = dst.set(n, item.clone());
}
dst
}
}
impl From<Value> for Array {
fn from(v: Value) -> Array {
if !v.is_block() {
let mut arr = Array::new(1);
let _ = arr.set(0, v);
arr
} else {
Array(v)
}
}
}
impl Array {
pub fn new(n: Size) -> Array {
unsafe {
let val = alloc::caml_alloc(n, Tag::Zero.into());
Array(Value::new(val))
}
}
pub fn is_double_array(&self) -> bool {
unsafe { alloc::caml_is_double_array(self.0.value()) == 1 }
}
pub fn len(&self) -> Size {
unsafe { mlvalues::caml_array_length(self.0.value()) }
}
pub fn set_double(&mut self, i: Size, f: f64) -> Result<(), Error> {
if i < self.len() {
if !self.is_double_array() {
return Err(Error::NotDoubleArray);
}
unsafe {
let ptr = self.0.ptr_val::<f64>().offset(i as isize) as *mut f64;
*ptr = f;
};
Ok(())
} else {
Err(Error::OutOfBounds)
}
}
pub fn get_double(&mut self, i: Size) -> Result<f64, Error> {
if i < self.len() {
if !self.is_double_array() {
return Err(Error::NotDoubleArray);
}
unsafe { Ok(*self.0.ptr_val::<f64>().offset(i as isize)) }
} else {
Err(Error::OutOfBounds)
}
}
pub fn set(&mut self, i: Size, v: Value) -> Result<(), Error> {
if i < self.len() {
self.0.store_field(i, v);
Ok(())
} else {
Err(Error::OutOfBounds)
}
}
pub fn get(&self, i: Size) -> Result<Value, Error> {
if i < self.len() {
Ok(self.0.field(i))
} else {
Err(Error::OutOfBounds)
}
}
}
pub struct List(Value);
impl From<List> for Value {
fn from(t: List) -> Value {
t.0
}
}
impl From<Value> for List {
fn from(v: Value) -> List {
if !v.is_block() {
let mut l = List::new();
let _ = l.push_hd(v);
l
} else {
List(v)
}
}
}
impl<R: AsRef<[Value]>> From<R> for List {
fn from(t: R) -> List {
let mut dst = List::new();
for item in t.as_ref().iter().rev() {
let _ = dst.push_hd(item.clone());
}
dst
}
}
impl List {
pub fn new() -> List {
List(Value::new(empty_list()))
}
pub fn len(&self) -> Size {
let mut length = 0;
let mut tmp = self.0.clone();
while tmp.value() != empty_list() {
tmp = tmp.field(1);
length += 1;
}
length
}
pub fn push_hd(&mut self, v: Value) {
unsafe {
let tmp = alloc::caml_alloc(2, 0);
memory::store_field(tmp, 0, v.0);
memory::store_field(tmp, 1, (self.0).0);
self.0 = Value::new(tmp);
}
}
pub fn hd(&self) -> Option<Value> {
if self.len() == 0 {
return None;
}
Some(self.0.field(0))
}
pub fn tl(&self) -> Value {
self.0.field(1)
}
}
pub struct Str(Value);
impl From<Str> for Value {
fn from(t: Str) -> Value {
t.0
}
}
impl<'a> From<&'a str> for Str {
fn from(s: &'a str) -> Str {
unsafe {
let len = s.len();
let x = alloc::caml_alloc_string(len);
let ptr = string_val!(x) as *mut u8;
ptr::copy(s.as_ptr(), ptr, len);
Str(Value::new(x))
}
}
}
impl<'a> From<&'a [u8]> for Str {
fn from(s: &'a [u8]) -> Str {
unsafe {
let len = s.len();
let x = alloc::caml_alloc_string(len);
let ptr = string_val!(x) as *mut u8;
ptr::copy(s.as_ptr(), ptr, len);
Str(Value::new(x))
}
}
}
impl From<Value> for Str {
fn from(v: Value) -> Str {
if v.tag() != Tag::String {
panic!("Invalid string value, got tag {:?}", v.tag());
} else {
Str(v)
}
}
}
impl Str {
pub fn new(n: Size) -> Str {
unsafe {
let s = alloc::caml_alloc_string(n);
Str(Value::new(s))
}
}
pub fn len(&self) -> Size {
unsafe { mlvalues::caml_string_length(self.0.value()) }
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn as_str(&self) -> &str {
let ptr = string_val!((self.0).0);
unsafe {
let slice = ::std::slice::from_raw_parts(ptr, self.len());
::std::str::from_utf8_unchecked(slice)
}
}
pub fn as_str_mut(&mut self) -> &mut str {
let ptr = string_val!((self.0).0) as *mut u8;
unsafe {
let slice = ::std::slice::from_raw_parts_mut(ptr, self.len());
::std::str::from_utf8_unchecked_mut(slice)
}
}
pub fn data(&self) -> &[u8] {
let ptr = string_val!((self.0).0);
unsafe { ::std::slice::from_raw_parts(ptr, self.len()) }
}
pub fn data_mut(&mut self) -> &mut [u8] {
let ptr = string_val!((self.0).0) as *mut u8;
unsafe { ::std::slice::from_raw_parts_mut(ptr, self.len()) }
}
}
pub trait BigarrayKind {
type T;
fn kind() -> i32;
}
macro_rules! make_kind {
($t:ty, $k:ident) => {
impl BigarrayKind for $t {
type T = $t;
fn kind() -> i32 {
bigarray::Kind::$k as i32
}
}
};
}
make_kind!(u8, UINT8);
make_kind!(i8, SINT8);
make_kind!(u16, UINT16);
make_kind!(i16, SINT16);
make_kind!(f32, FLOAT32);
make_kind!(f64, FLOAT64);
make_kind!(i64, INT64);
make_kind!(i32, INT32);
make_kind!(char, CHAR);
pub struct Array1<T>(Value, PhantomData<T>);
impl<T: BigarrayKind> From<Array1<T>> for Value {
fn from(t: Array1<T>) -> Value {
t.0
}
}
impl<T: BigarrayKind> From<Value> for Array1<T> {
fn from(v: Value) -> Array1<T> {
Array1(v, PhantomData)
}
}
impl<T: BigarrayKind> Array1<T> {
pub fn of_slice(data: &mut [T]) -> Array1<T> {
unsafe {
let s = bigarray::caml_ba_alloc_dims(
T::kind() | bigarray::Managed::EXTERNAL as i32,
1,
data.as_mut_ptr() as bigarray::Data,
data.len() as i32,
);
Array1(Value::new(s), PhantomData)
}
}
pub fn create(n: Size) -> Array1<T> {
unsafe {
let data = bigarray::malloc(n * mem::size_of::<T>());
let s = bigarray::caml_ba_alloc_dims(
T::kind() | bigarray::Managed::MANAGED as i32,
1,
data,
n as mlvalues::Intnat,
);
Array1(Value::new(s), PhantomData)
}
}
pub fn len(&self) -> Size {
let ba = self.0.custom_ptr_val::<bigarray::Bigarray>();
unsafe { (*ba).dim as usize }
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn data(&self) -> &[T] {
let ba = self.0.custom_ptr_val::<bigarray::Bigarray>();
unsafe { slice::from_raw_parts((*ba).data as *const T, self.len()) }
}
pub fn data_mut(&mut self) -> &mut [T] {
let ba = self.0.custom_ptr_val::<bigarray::Bigarray>();
unsafe { slice::from_raw_parts_mut((*ba).data as *mut T, self.len()) }
}
}