From d6b6dd033b85dc68c9c2d46f7d2612da393d363c Mon Sep 17 00:00:00 2001 From: Nikolay Murzin Date: Tue, 24 Oct 2023 10:25:01 +0300 Subject: [PATCH] Support Vec and HashMap with DataStore --- wolfram-library-link/src/args.rs | 90 ++++++++++++++ wolfram-library-link/src/data_store.rs | 158 +++++++++++++++++++++++++ 2 files changed, 248 insertions(+) diff --git a/wolfram-library-link/src/args.rs b/wolfram-library-link/src/args.rs index 688974d..62ffcb8 100644 --- a/wolfram-library-link/src/args.rs +++ b/wolfram-library-link/src/args.rs @@ -3,6 +3,7 @@ use std::{ cell::RefCell, + collections::HashMap, ffi::{CStr, CString}, os::raw::c_char, }; @@ -10,6 +11,7 @@ use std::{ use ref_cast::RefCast; use crate::{ + data_store::{DataStoreAdd, DataStoreNodeValue}, expr::{Expr, Symbol}, rtl, sys::{self, mint, mreal, MArgument}, @@ -254,6 +256,16 @@ impl<'a> FromArg<'a> for &'a str { } } +impl FromArg<'_> for char { + unsafe fn from_arg(arg: &MArgument) -> Self { + String::from_arg(arg).chars().next().unwrap() + } + + fn parameter_type() -> Expr { + String::parameter_type() + } +} + //-------------------------------------- // NumericArray //-------------------------------------- @@ -456,6 +468,61 @@ impl<'a> FromArg<'a> for &'a DataStore { } } +impl From>> FromArg<'_> for Vec { + unsafe fn from_arg(arg: &MArgument) -> Vec { + let mut vec = Vec::new(); + DataStore::from_arg(arg) + .nodes() + .for_each(|node| vec.push(T::from(node.value()))); + vec + } + + fn parameter_type() -> Expr { + Expr::string("DataStore") + } +} + +impl< + K: for<'a> From> + Eq + std::hash::Hash, + V: for<'a> From>, + S: Default + std::hash::BuildHasher, + > FromArg<'_> for HashMap +{ + unsafe fn from_arg(arg: &MArgument) -> HashMap { + let mut dict = HashMap::default(); + DataStore::from_arg(arg) + .nodes() + .for_each(|node| match node.value() { + DataStoreNodeValue::DataStore(rule) => { + let mut nodes = rule.nodes(); + let k = K::from(nodes.next().unwrap().value()); + let v = V::from(nodes.next().unwrap().value()); + dict.insert(k, v); + () + }, + _ => panic!("Expected DataStore of DataStores"), + }); + dict + } + + fn parameter_type() -> Expr { + Expr::string("DataStore") + } +} + +impl From>> FromArg<'_> for Option { + unsafe fn from_arg(arg: &MArgument) -> Option { + match DataStore::from_arg(arg).nodes().next() { + None => None, + Some(v) => Some(T::from(v.value())), + } + } + + fn parameter_type() -> Expr { + Expr::string("DataStore") + } +} + //====================================== // impl IntoArg //====================================== @@ -644,6 +711,16 @@ impl IntoArg for String { } } +impl IntoArg for char { + unsafe fn into_arg(self, arg: MArgument) { + String::from(self).into_arg(arg) + } + + fn return_type() -> Expr { + String::return_type() + } +} + //--------------------------------------- // NumericArray, Image, DataStore //--------------------------------------- @@ -703,6 +780,19 @@ impl IntoArg for DataStore { } } + +impl IntoArg for Vec { + unsafe fn into_arg(self, arg: MArgument) { + let mut store = DataStore::new(); + self.iter().for_each(|x| x.add_to_datastore(&mut store)); + store.into_arg(arg) + } + + fn return_type() -> Expr { + Expr::string("DataStore") + } +} + //====================================== // impl NativeFunction //====================================== diff --git a/wolfram-library-link/src/data_store.rs b/wolfram-library-link/src/data_store.rs index 79a739c..4fdd0dd 100644 --- a/wolfram-library-link/src/data_store.rs +++ b/wolfram-library-link/src/data_store.rs @@ -600,6 +600,164 @@ impl<'store> DataStoreNode<'store> { } } +//--------------- +// DataStoreAdd trait +//--------------- + +pub trait DataStoreAdd { + fn add_to_datastore(&self, ds: &mut DataStore); +} + +impl DataStoreAdd for bool { + fn add_to_datastore(&self, ds: &mut DataStore) { + ds.add_bool(*self) + } +} + +impl DataStoreAdd for &str { + fn add_to_datastore(&self, ds: &mut DataStore) { + ds.add_str(*self) + } +} + +impl DataStoreAdd for char { + fn add_to_datastore(&self, ds: &mut DataStore) { + String::from(*self).as_str().add_to_datastore(ds) + } +} + +impl DataStoreAdd for u16 { + fn add_to_datastore(&self, ds: &mut DataStore) { + ds.add_i64(*self as i64) + } +} + +impl DataStoreAdd for DataStore { + fn add_to_datastore(&self, ds: &mut DataStore) { + ds.add_data_store(self.clone()) + } +} + +impl DataStoreAdd for Vec { + fn add_to_datastore(&self, ds: &mut DataStore) { + let mut inner = DataStore::new(); + self.into_iter().for_each(|item| item.add_to_datastore(&mut inner)); + ds.add_data_store(inner) + } +} + +//--------------- +// From DataStoreNodeValue +//--------------- + +impl From> for bool { + fn from(value: DataStoreNodeValue) -> bool { + match value { + DataStoreNodeValue::Boolean(val) => val, + _ => panic!("expected DataStoreNodeValue::Boolean"), + } + } +} + +impl From> for mint { + fn from(value: DataStoreNodeValue) -> mint { + match value { + DataStoreNodeValue::Integer(val) => val, + _ => panic!("expected DataStoreNodeValue::Integer"), + } + } +} + +impl From> for mreal { + fn from(value: DataStoreNodeValue) -> mreal { + match value { + DataStoreNodeValue::Real(val) => val, + _ => panic!("expected DataStoreNodeValue::Real"), + } + } +} + +impl From> for f32 { + fn from(value: DataStoreNodeValue) -> f32 { + match value { + DataStoreNodeValue::Real(val) => val as f32, + _ => panic!("expected DataStoreNodeValue::Real"), + } + } +} + +impl From> for mcomplex { + fn from(value: DataStoreNodeValue) -> mcomplex { + match value { + DataStoreNodeValue::Complex(val) => val, + _ => panic!("expected DataStoreNodeValue::Complex"), + } + } +} + +impl<'node> From> for &'node str { + fn from(value: DataStoreNodeValue<'node>) -> &'node str { + match value { + DataStoreNodeValue::Str(val) => val, + _ => panic!("expected DataStoreNodeValue::Str"), + } + } +} + +impl<'node> From> for String { + fn from(value: DataStoreNodeValue<'node>) -> String { + match value { + DataStoreNodeValue::Str(val) => String::from(val), + _ => panic!("expected DataStoreNodeValue::Str"), + } + } +} + +impl From> for char { + fn from(value: DataStoreNodeValue) -> char { + match value { + DataStoreNodeValue::Str(val) => String::from(val).chars().next().unwrap(), + _ => panic!("expected DataStoreNodeValue::Str"), + } + } +} + +impl<'node> From> for &'node NumericArray { + fn from(value: DataStoreNodeValue<'node>) -> &'node NumericArray { + match value { + DataStoreNodeValue::NumericArray(val) => val, + _ => panic!("expected DataStoreNodeValue::NumericArray"), + } + } +} + +impl<'node> From> for &'node Image { + fn from(value: DataStoreNodeValue<'node>) -> &'node Image { + match value { + DataStoreNodeValue::Image(val) => val, + _ => panic!("expected DataStoreNodeValue::Image"), + } + } +} + +impl<'node> From> for &'node DataStore { + fn from(value: DataStoreNodeValue<'node>) -> &'node DataStore { + match value { + DataStoreNodeValue::DataStore(val) => val, + _ => panic!("expected DataStoreNodeValue::DataStore"), + } + } +} + +impl<'node, T: for<'a> From>> From> for Vec { + fn from(value: DataStoreNodeValue<'node>) -> Vec { + match value { + DataStoreNodeValue::DataStore(val) => val.nodes().map(|n| n.value().into()).collect(), + _ => panic!("expected DataStoreNodeValue::DataStore"), + } + } +} + //--------------- // Nodes iterator //---------------