#![allow(unused_unsafe)]
use std::os::raw::c_void;
use core::fmt::Debug;
use core::ops::DerefMut;
use std::slice::{
from_raw_parts,
from_raw_parts_mut
};
use ndarray::{
Array,
ArrayViewD,
ArrayViewMutD,
Dimension,
};
pub use rustmex_core::numeric::{
MatlabNumber,
NumericArray,
MutNumericArray,
};
use rustmex_core::{
mxArray,
pointers::{
MxArray,
MatlabPtr,
MutMatlabPtr,
},
num_struct,
data_or_dangling,
data_shape_ok,
mappable::*,
convert::{
ToMatlabResult,
FromVec,
VecLayout,
FromMatlabError,
},
shim::{
rustmex_create_uninit_numeric_array,
},
MatlabClass,
MutMatlabClass,
OwnedMatlabClass,
NewEmpty,
TakeData,
Complexity,
raw::{
mwSize,
mxClassID,
},
};
#[cfg(any(doc, all(feature = "complex", feature="matlab800")))]
pub use rustmex_interleaved_complex::InterleavedComplexArray;
#[cfg(any(doc, all(feature = "complex", any(feature="matlab700", feature="octave"))))]
pub use rustmex_separated_complex::SeparatedComplexArray;
#[cfg(any(doc, all(feature="complex", feature="matlab800")))]
pub use InterleavedComplexArray as ComplexArray;
#[cfg(all(feature="complex", any(feature="matlab700", feature="octave")))]
pub use SeparatedComplexArray as ComplexArray;
num_struct!(
Numeric, Complexity::Real);
pub type OwnedNumeric<T> = Numeric<T, MxArray>;
extern "Rust" {
fn rustmex_set_real_data(mx: *mut mxArray, newdata: Real<*mut c_void>);
fn rustmex_get_real_data(mx: *const mxArray) -> Real<*mut c_void>;
}
macro_rules! data_access {
($s:ident, $t1:ty, $accessor:ident, $builder:ident) => {{
let ptr = data_or_dangling!(unsafe { $accessor($s.array.deref()) }.0, $t1 );
let numel = $s.array.numel();
unsafe { $builder(ptr, numel) }
}}
}
impl<'p, T, P> NumericArray<'p> for Numeric<T, P> where
T: MatlabNumber + 'p,
P: MatlabPtr + 'p,
{
type Data = &'p [T];
fn data(&self) -> Self::Data {
data_access!(self, *const T, rustmex_get_real_data, from_raw_parts)
}
}
impl<'p, T, P> MutNumericArray<'p> for Numeric<T, P> where
T: MatlabNumber + 'p,
P: MutMatlabPtr + 'p,
{
type MutData = &'p mut [T];
fn mut_data(&mut self) -> Self::MutData {
data_access!(self, *mut T, rustmex_get_real_data, from_raw_parts_mut)
}
}
impl<T, P> TakeData<P> for Numeric<T, P> where
T: MatlabNumber,
P: MutMatlabPtr,
{
type OwnedData = Box<[T]>;
fn take_data(&mut self) -> Self::OwnedData {
let data = self.mut_data();
let data = unsafe { Vec::from_raw_parts(data.as_mut_ptr(), data.len(), data.len()) }
.into_boxed_slice();
unsafe { rustmex_set_real_data(self.deref_mut(), Real(core::ptr::null_mut())) };
data
}
}
macro_rules! construct_set {
($data:ident, $shape:ident, $complex:literal) => {{
data_shape_ok!($data, $shape);
let mx = rustmex_core::create_uninit_numeric_array!($shape, T, Complexity::Real);
unsafe { rustmex_set_real_data(mx, Real(Box::into_raw($data) as *mut core::ffi::c_void)); }
mx
}}
}
impl<T: MatlabNumber> Numeric<T, MxArray> {
pub fn new(data: Box<[T]>, shape: &[usize]) -> ToMatlabResult<Self, Box<[T]>> {
Ok(Self::construct(unsafe {MxArray::assume_responsibility_ptr(construct_set!(data, shape, false))}))
}
}
impl<'a, T> From<Numeric<T, &'a mxArray>> for ArrayViewD<'a, T> where
T: MatlabNumber
{
fn from(num: Numeric<T, &'a mxArray>) -> Self {
(&num).into()
}
}
impl<'a, T> From<&Numeric<T, &'a mxArray>> for ArrayViewD<'a, T> where
T: MatlabNumber
{
fn from(num: &Numeric<T, &'a mxArray>) -> Self {
let data = num.data();
let dims = num.dimensions();
rustmex_core::from_num_to_ndarray!(data, dims)
}
}
impl<'a, T> From<&Numeric<T, &'a mxArray>> for &'a [T] where
T: MatlabNumber
{
fn from(num: &Numeric<T, &'a mxArray>) -> Self {
num.data()
}
}
impl<'a, T> From<Numeric<T, &'a mxArray>> for &'a [T] where
T: MatlabNumber
{
fn from(num: Numeric<T, &'a mxArray>) -> Self {
num.into()
}
}
impl<'a, T> From<Numeric<T, &'a mut mxArray>> for ArrayViewMutD<'a, T> where
T: MatlabNumber
{
fn from(mut num: Numeric<T, &'a mut mxArray>) -> Self {
(&mut num).into()
}
}
impl<'a, T> From<&mut Numeric<T, &'a mut mxArray>> for ArrayViewMutD<'a, T> where
T: MatlabNumber,
{
fn from(num: &mut Numeric<T, &'a mut mxArray>) -> Self {
let data = num.mut_data();
let dims = num.dimensions();
rustmex_core::from_num_to_ndarray!(data, dims)
}
}
impl<'a, T, D> From<Array<T, D>> for Numeric<T, MxArray> where
T: MatlabNumber,
D: Dimension,
{
fn from(mut arr: Array<T, D>) -> Self {
rustmex_core::from_ndarray_to_num!(arr)
}
}
impl<T> From<T> for Numeric<T, MxArray> where T: MatlabNumber {
fn from(t: T) -> Self {
Numeric::new(Box::new([t]), &[1, 1]).unwrap()
}
}
impl<T> From<[T;0]> for Numeric<T, MxArray> where T: MatlabNumber {
fn from(_empty: [T;0]) -> Self {
Self::new_empty()
}
}
impl From<()> for Numeric<f64, MxArray> {
fn from(_nothing: ()) -> Self {
Self::new_empty()
}
}
impl<T> FromVec<T> for Numeric<T, MxArray> where T: MatlabNumber {
fn from_boxed_slice<L: VecLayout>(b: Box<[T]>, l: L) -> Self {
let len = b.len();
Self::new(b, l.layout(len).as_ref()).expect("Conversion from Vec-ish type should be infallible")
}
}