From 5fac5c8da9108f4124217a8e42750b0347f18898 Mon Sep 17 00:00:00 2001 From: Federico Lolli <federico.lolli@skywarder.eu> Date: Mon, 19 Feb 2024 00:24:27 +0100 Subject: [PATCH] building main --- src/error.rs | 71 ++++++++++++++++++++++++++++++++++ src/lib.rs | 31 +++++++++++++++ src/main.rs | 3 -- src/types.rs | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 207 insertions(+), 3 deletions(-) create mode 100644 src/error.rs create mode 100644 src/lib.rs delete mode 100644 src/main.rs create mode 100644 src/types.rs diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..29a57c7 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,71 @@ +use rustmex::{message::AdHoc, mxArray, FromMatlabError}; + +pub trait MapMexError<T> { + fn map_err_adhoc(self, id: &str, msg: &str) -> Result<T, rustmex::Error>; + fn mexerr(self, err: Error) -> Result<T, rustmex::Error>; +} + +impl<T, E> MapMexError<T> for Result<T, E> { + fn map_err_adhoc(self, id: &str, msg: &str) -> Result<T, rustmex::Error> { + Ok(self.map_err(|_| AdHoc(id, msg))?) + } + + fn mexerr(self, err: Error) -> Result<T, rustmex::Error> { + self.map_err(|_| err.to_mexerr()) + } +} + +impl<T> MapMexError<T> for Option<T> { + fn map_err_adhoc(self, id: &str, msg: &str) -> Result<T, rustmex::Error> { + Ok(self.ok_or(AdHoc(id, msg))?) + } + + fn mexerr(self, err: Error) -> Result<T, rustmex::Error> { + self.ok_or_else(|| err.to_mexerr()) + } +} + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("Missing serial mode (first argument)")] + MissingSerialMode, + #[error("Missing port name (second argument)")] + MissingPortName, + #[error("Missing baudrate (third argument)")] + MissingBaudrate, + #[error("String contains invalid characters")] + String(#[from] std::ffi::IntoStringError), + #[error("Invalid serial mode")] + InvalidMode, + #[error("{0}")] + Rustmex(#[from] rustmex::Error), +} + +impl Error { + fn id(&self) -> &str { + match self { + Error::MissingSerialMode => "serialbridge:missing_input", + Error::MissingPortName => "serialbridge:missing_input", + Error::MissingBaudrate => "serialbridge:missing_input", + Error::String(_) => "serialbridge:invalid_input", + Error::InvalidMode => "serialbridge:invalid_input", + Error::Rustmex(err) => err.id(), + } + } + + pub fn to_mexerr(&self) -> rustmex::Error { + AdHoc(self.id(), self.to_string()).into() + } +} + +impl From<Error> for rustmex::Error { + fn from(err: Error) -> Self { + err.to_mexerr() + } +} + +impl From<FromMatlabError<&mxArray>> for Error { + fn from(err: FromMatlabError<&mxArray>) -> Self { + err.into() + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..9badc03 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,31 @@ +//! WARNING: panic is used as stated in the example at +//! [rustmex](https://gitlab.com/nielstermeer/rustmex/-/blob/master/examples/catch_panic/src/lib.rs?ref_type=heads). + +mod error; +mod types; + +use rustmex::{char::CharArray, prelude::*, MatlabClass}; + +use error::{Error, MapMexError}; + +#[rustmex::entrypoint] +fn serialbridge(lhs: Lhs, rhs: Rhs) -> rustmex::Result<()> { + let arg0 = rhs.first().mexerr(Error::MissingSerialMode)?; + + // Get the mode argument ("Open", "Close", "Read", "Write") + let mode = get_mode(arg0); + + let arg1 = rhs.get(1).error_if_missing( + "serialbridge:missing_input", + "Missing serial mode (second argument)", + )?; + + Ok(()) +} + +fn get_mode(arg: &mxArray) -> Result<types::Mode, Error> { + CharArray::from_mx_array(arg)? + .get_cstring() + .into_string()? + .parse() +} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/src/types.rs b/src/types.rs new file mode 100644 index 0000000..1e58747 --- /dev/null +++ b/src/types.rs @@ -0,0 +1,105 @@ +use std::{ + ffi::{CStr, CString}, + ops::Deref, + str::FromStr, +}; + +use cstr::cstr; +use rustmex::{ + convert::ToMatlab, + error, + numeric::{Numeric, NumericArray}, + structs::{ScalarStruct, Struct}, + MatlabClass, MxArray, +}; + +use crate::error::Error; + +#[derive(Debug, Clone)] +pub struct Serial(ScalarStruct<MxArray>); + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Mode { + Open, + Close, + Read, + Write, +} + +impl FromStr for Mode { + type Err = crate::Error; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "Open" => Ok(Mode::Open), + "Close" => Ok(Mode::Close), + "Read" => Ok(Mode::Read), + "Write" => Ok(Mode::Write), + _ => Err(Error::InvalidMode), + } + } +} + +// #[derive(Debug, Clone)] +// struct ByteString(MxArray); + +// impl From<&str> for ByteString { +// fn from(value: &str) -> Self { +// let raw = value.as_bytes(); +// Self( +// Numeric::new(raw.into(), &[1, raw.len()]) +// .expect("Failed to create byte string") +// .into_inner(), +// ) +// } +// } + +// impl ByteString { +// fn from_string(value: String) -> Self { +// value.as_str().into() +// } + +// fn into_string(self) -> rustmex::Result<String> { +// let value = Numeric::<u8, MxArray>::from_mx_array(self.0)?.data(); +// Ok(String::from_utf8(value.to_vec()).expect("Failed to convert byte string to string")) +// } +// } + +// impl Deref for ByteString { +// type Target = MxArray; + +// fn deref(&self) -> &Self::Target { +// &self.0 +// } +// } + +// impl Serial { +// pub fn new(device: String, baudrate: u32) -> Self { +// let device_f = cstr!("serialport"); +// let baud_f = cstr!("baudrate"); +// let mut s = Struct::new(&[1, 1], &[device_f, baud_f]) +// .into_scalar() +// .unwrap(); +// // let device = CString::new(device.into()).unwrap(); +// s.set(device_f, *ByteString::from_string(device)).unwrap(); +// s.set(baud_f, baudrate.to_matlab()).unwrap(); +// Serial(s) +// } + +// pub fn into_struct(self) -> ScalarStruct<MxArray> { +// self.0 +// } + +// pub fn from_struct(s: ScalarStruct<MxArray>) -> Self { +// Serial(s) +// } + +// pub fn device(&self) -> rustmex::Result<String> { +// let device_f = cstr!("serialport"); +// let a = self +// .0 +// .get(device_f) +// .map(|x| x.ok_or_else(|| error!("serialbridge:missing_input", "Device not found")))? +// .map(|x| ByteString(x.to_owned())); +// } +// } -- GitLab