matio-rs 0.1.1

Rust wrapper to MATLAB MAT file I/O library
Documentation
use crate::{MatioError, Result};
use std::{
    any::{type_name, TypeId},
    fmt::Display,
    marker::PhantomData,
    ptr,
};

mod datatype;
pub use datatype::DataType;

/// Matlab variable
pub struct MatVar<T> {
    pub(crate) matvar_t: *mut ffi::matvar_t,
    pub(crate) data_type: PhantomData<T>,
}
impl<T> Drop for MatVar<T> {
    fn drop(&mut self) {
        unsafe {
            ffi::Mat_VarFree(self.matvar_t);
        }
    }
}
impl<T> Display for MatVar<T> {
    fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        unsafe { ffi::Mat_VarPrint(self.matvar_t, 0) }
        Ok(())
    }
}
impl<T: 'static> MatVar<T> {
    /// Checks Rust and Matlab types compatibility
    pub fn match_types(self) -> Result<Self> {
        unsafe {
            if (TypeId::of::<T>() == TypeId::of::<f64>()
                || TypeId::of::<T>() == TypeId::of::<Vec<f64>>())
                && (*self.matvar_t).data_type == ffi::matio_types_MAT_T_DOUBLE
            {
                return Ok(self);
            }
            Err(MatioError::MatType(
                type_name::<T>().to_string(),
                {
                    match (*self.matvar_t).data_type {
                        ffi::matio_types_MAT_T_DOUBLE => "DOUBLE",
                        _ => "UNKNOWN",
                    }
                }
                .to_string(),
            ))
        }
    }
}

impl<T: DataType> MatVar<T> {
    /// Creates a new Matlab variable `name`
    pub fn new<S: Into<String>>(name: S, mut data: T) -> Result<Self> {
        let c_name = std::ffi::CString::new(name.into())?;
        let mut dims = [1, 1];
        let matvar_t = unsafe {
            ffi::Mat_VarCreate(
                c_name.as_ptr(),
                <T as DataType>::mat_c(),
                <T as DataType>::mat_t(),
                2,
                dims.as_mut_ptr(),
                &mut data as *mut _ as *mut std::ffi::c_void,
                0,
            )
        };
        if matvar_t.is_null() {
            Err(MatioError::MatVarCreate(
                c_name.to_str().unwrap().to_string(),
            ))
        } else {
            Ok(MatVar {
                matvar_t,
                data_type: PhantomData,
            })
        }
    }
}
impl<T: DataType> MatVar<Vec<T>> {
    /// Creates a new Matlab variable `name`
    pub fn new<S: Into<String>>(name: S, data: &mut [T]) -> Result<Self> {
        let c_name = std::ffi::CString::new(name.into())?;
        let mut dims = [1, data.len() as u64];
        let matvar_t = unsafe {
            ffi::Mat_VarCreate(
                c_name.as_ptr(),
                <T as DataType>::mat_c(),
                <T as DataType>::mat_t(),
                2,
                dims.as_mut_ptr(),
                data.as_mut_ptr() as *mut std::ffi::c_void,
                0,
            )
        };
        if matvar_t.is_null() {
            Err(MatioError::MatVarCreate(
                c_name.to_str().unwrap().to_string(),
            ))
        } else {
            Ok(MatVar {
                matvar_t,
                data_type: PhantomData,
            })
        }
    }
    pub fn array<S: Into<String>>(
        name: S,
        data: &mut [f64],
        shape: (usize, usize),
    ) -> Result<Self> {
        let c_name = std::ffi::CString::new(name.into())?;
        let mut dims = [shape.0 as u64, shape.1 as u64];
        let matvar_t = unsafe {
            ffi::Mat_VarCreate(
                c_name.as_ptr(),
                ffi::matio_classes_MAT_C_DOUBLE,
                ffi::matio_types_MAT_T_DOUBLE,
                2,
                dims.as_mut_ptr(),
                data.as_mut_ptr() as *mut std::ffi::c_void,
                0,
            )
        };
        if matvar_t.is_null() {
            Err(MatioError::MatVarCreate(
                c_name.to_str().unwrap().to_string(),
            ))
        } else {
            Ok(MatVar {
                matvar_t,
                data_type: PhantomData,
            })
        }
    }
}

macro_rules! scalar {
    ( $( $rs:ty ),+ ) => {
	$(
        impl From<MatVar<$rs>> for $rs {
            fn from(mat_var: MatVar<$rs>) -> Self {
                unsafe { ((*mat_var.matvar_t).data as *mut $rs).read() }
            }
        }
	    )+
    };
}
scalar!(f64, f32, i8, i16, i32, i64, u8, u16, u32, u64);

impl<T: DataType> From<MatVar<Vec<T>>> for Vec<T> {
    fn from(mat_var: MatVar<Vec<T>>) -> Self {
        unsafe {
            let rank = (*mat_var.matvar_t).rank as usize;
            let mut dims: Vec<u64> = Vec::with_capacity(rank);
            ptr::copy((*mat_var.matvar_t).dims, dims.as_mut_ptr(), rank);
            dims.set_len(rank);
            let length = dims.into_iter().product::<u64>() as usize;

            let mut value: Vec<T> = Vec::with_capacity(length);
            ptr::copy(
                (*mat_var.matvar_t).data as *mut T,
                value.as_mut_ptr(),
                length,
            );
            value.set_len(length);
            value
        }
    }
}

#[cfg(feature = "nalgebra")]
impl<T> From<MatVar<Vec<T>>> for nalgebra::DVector<T>
where
    T: 'static + DataType + Clone + std::fmt::Debug + PartialEq,
{
    fn from(mat_var: MatVar<Vec<T>>) -> Self {
        let v: Vec<T> = mat_var.into();
        nalgebra::DVector::from_vec(v)
    }
}
#[cfg(feature = "nalgebra")]
impl<T> From<MatVar<Vec<T>>> for Option<nalgebra::DMatrix<T>>
where
    T: 'static + DataType + Clone + std::fmt::Debug + PartialEq,
{
    fn from(mat_var: MatVar<Vec<T>>) -> Self {
        unsafe {
            let rank = (*mat_var.matvar_t).rank as usize;
            if rank > 2 {
                None
            } else {
                let mut dims: Vec<u64> = Vec::with_capacity(rank);
                ptr::copy((*mat_var.matvar_t).dims, dims.as_mut_ptr(), rank);
                dims.set_len(rank);
                let (n, m) = (dims[0] as usize, dims[1] as usize);
                let length = dims.into_iter().product::<u64>() as usize;
                let mut value: Vec<T> = Vec::with_capacity(length);
                ptr::copy(
                    (*mat_var.matvar_t).data as *mut T,
                    value.as_mut_ptr(),
                    length,
                );
                value.set_len(length);
                Some(nalgebra::DMatrix::from_vec(n, m, value))
            }
        }
    }
}