From 8cef261f1ed246b84e83940af6c3f9e3017a248b Mon Sep 17 00:00:00 2001 From: hulxv Date: Mon, 25 Nov 2024 23:19:44 +0200 Subject: [PATCH] feat(rs-port2): build the base of the values - implement a constructor and `get_value` for - i16, i32, i64 - f32, f64 - String, &str - implement those methods for Value: - `is_null()` - `value_id()` - `value_id_name()` --- source/ports/rs_port2/src/value.rs | 54 --------- source/ports/rs_port2/src/value/float.rs | 51 ++++++++ source/ports/rs_port2/src/value/int.rs | 61 ++++++++++ source/ports/rs_port2/src/value/mod.rs | 135 ++++++++++++++++++++++ source/ports/rs_port2/src/value/string.rs | 44 +++++++ source/ports/rs_port2/src/value/tests.rs | 0 6 files changed, 291 insertions(+), 54 deletions(-) delete mode 100644 source/ports/rs_port2/src/value.rs create mode 100644 source/ports/rs_port2/src/value/float.rs create mode 100644 source/ports/rs_port2/src/value/int.rs create mode 100644 source/ports/rs_port2/src/value/mod.rs create mode 100644 source/ports/rs_port2/src/value/string.rs create mode 100644 source/ports/rs_port2/src/value/tests.rs diff --git a/source/ports/rs_port2/src/value.rs b/source/ports/rs_port2/src/value.rs deleted file mode 100644 index 6141cc0bd..000000000 --- a/source/ports/rs_port2/src/value.rs +++ /dev/null @@ -1,54 +0,0 @@ -use metacall_bindings::value::{ - create::metacall_value_create_long, metacall_value_destroy, metacall_value_from_long, - metacall_value_to_long, -}; -use thiserror::Error; -} - -#[derive(Error, Debug)] -pub enum ValueError { - #[error("Failed to create CString: {0}")] - CStringError(#[from] std::ffi::NulError), - #[error("Failed to convert CString to &str: {0}")] - Utf8Error(#[from] std::str::Utf8Error), - #[error("Null pointer encountered")] - NullPointer, - #[error("Unknown error")] - Unknown, -} -} - -impl To for Value { - fn to(&self) -> i64 { - unsafe { metacall_value_to_long(self.0) as i64 } - } -} - -impl Drop for Value { - fn drop(&mut self) { - unsafe { - metacall_value_destroy(self.0); - } - } -} - -#[cfg(test)] -mod test { - // use metacall_bindings::{metacall_destroy, metacall_initialize}; - - use super::{Create, From, To, Value}; - - #[test] - fn metacall_create_value() { - // assert!(unsafe { metacall_initialize() } == 0); - let mut val = Value::new(123); - let result = val.to(); - assert!(result == 123); - val.from(33); - - let result = val.to(); - println!("{}", result); // 33 - assert!(result == 33); - // unsafe { metacall_destroy() }; - } -} diff --git a/source/ports/rs_port2/src/value/float.rs b/source/ports/rs_port2/src/value/float.rs new file mode 100644 index 000000000..6840580d7 --- /dev/null +++ b/source/ports/rs_port2/src/value/float.rs @@ -0,0 +1,51 @@ +use std::marker::PhantomData; + +use crate::{check_null_ptr, impl_value_constructor}; + +use super::{Value, ValueError}; +use anyhow::Result; +use metacall_bindings::value::{ + create::{metacall_value_create_double, metacall_value_create_float}, + metacall_value_to_double, metacall_value_to_float, +}; +impl Value { + pub fn get_value(&self) -> Result { + let res = unsafe { metacall_value_to_float(self.ptr).to_owned() }; + + Ok(res) + } +} + +impl_value_constructor!( + value => { + let ptr = unsafe { metacall_value_create_float(value.into()) }; + + check_null_ptr!(ptr, ValueError::NullPointer); + + Ok(Self { + ptr, + _phantom: PhantomData, + }) + }, f32 +); + +impl Value { + pub fn get_value(&self) -> Result { + let res = unsafe { metacall_value_to_double(self.ptr).to_owned() }; + + Ok(res) + } +} + +impl_value_constructor!( + value => { + let ptr = unsafe { metacall_value_create_double(value) }; + + check_null_ptr!(ptr, ValueError::NullPointer); + + Ok(Self { + ptr, + _phantom: PhantomData, + }) + }, f64 +); diff --git a/source/ports/rs_port2/src/value/int.rs b/source/ports/rs_port2/src/value/int.rs new file mode 100644 index 000000000..42e031208 --- /dev/null +++ b/source/ports/rs_port2/src/value/int.rs @@ -0,0 +1,61 @@ +use std::marker::PhantomData; + +use anyhow::Result; +use metacall_bindings::value::{ + create::{metacall_value_create_int, metacall_value_create_long}, + metacall_value_to_int, metacall_value_to_long, +}; + +use crate::{check_null_ptr, impl_value_constructor}; + +use super::{Value, ValueError}; + +impl Value { + pub fn get_value(&self) -> Result { + let res = unsafe { metacall_value_to_long(self.ptr).to_owned() }; + + Ok(res) + } +} + +impl_value_constructor!( + value => { + let ptr = unsafe { metacall_value_create_long(value) }; + + check_null_ptr!(ptr, ValueError::NullPointer); + + Ok(Self { + ptr, + _phantom: PhantomData, + }) + }, i64 +); + +impl Value { + pub fn get_value(&self) -> Result { + let res = unsafe { metacall_value_to_int(self.ptr).to_owned() }; + + Ok(res) + } +} + +impl Value { + pub fn get_value(&self) -> Result { + let res: i16 = unsafe { metacall_value_to_int(self.ptr).to_owned() }.try_into()?; + + Ok(res) + } +} + +impl_value_constructor!( + value => { + let ptr = unsafe { metacall_value_create_int(value.into()) }; + + check_null_ptr!(ptr, ValueError::NullPointer); + + Ok(Self { + ptr, + _phantom: PhantomData, + }) + }, i16, i32 +); diff --git a/source/ports/rs_port2/src/value/mod.rs b/source/ports/rs_port2/src/value/mod.rs new file mode 100644 index 000000000..76865f64c --- /dev/null +++ b/source/ports/rs_port2/src/value/mod.rs @@ -0,0 +1,135 @@ +mod float; +mod int; +mod string; + +use anyhow::Result; +use metacall_bindings::value::{ + metacall_value_destroy, metacall_value_id, metacall_value_id_name, metacall_value_type_name, + MetacallValueID, +}; +use std::{ + ffi::{c_void, CStr}, + marker::PhantomData, + ptr::null_mut, +}; +use thiserror::Error; + +use crate::check_null_ptr; + +#[macro_export] +macro_rules! impl_value_constructor { + ($value:ident => $code:block, $($type:ty),+) => { + $( + impl Value<$type> { + pub fn new($value: $type) -> Result { + $code + } + } + )+ + }; +} + +#[derive(Error, Debug)] +pub enum ValueError { + #[error("Failed to create CString: {0}")] + CStringError(#[from] std::ffi::NulError), + #[error("Failed to convert CString to &str: {0}")] + Utf8Error(#[from] std::str::Utf8Error), + #[error("Null pointer encountered")] + NullPointer, + #[error("Unknown error")] + Unknown, +} + +pub struct Value { + ptr: *mut c_void, + _phantom: PhantomData, +} + +impl Value { + /// A simple method to check the nullity of the Value. + pub fn is_null(&self) -> Result { + let id = self.value_id()?; + Ok(id == MetacallValueID::Null) + } + + /// Provides the type identifier (ID). + pub fn value_id(&self) -> Result { + check_null_ptr!(self.ptr, ValueError::NullPointer); + let id = unsafe { metacall_value_id(self.ptr) }; + Ok(id) + } + + /// Provides the type identifier (ID) in a readable form (as a `String`). + pub fn value_id_name(&self) -> Result { + check_null_ptr!(self.ptr, ValueError::NullPointer); + let ptr = unsafe { metacall_value_type_name(self.ptr) }; + let c_str = unsafe { CStr::from_ptr(ptr) }.to_str()?; + Ok(c_str.to_string()) + } +} + +impl Drop for Value { + fn drop(&mut self) { + unsafe { + metacall_value_destroy(self.ptr); + self.ptr = null_mut(); + } + } +} + +#[cfg(test)] +mod test { + + use super::Value; + #[test] + fn metacall_create_value_string() { + let string = String::from("Hello!"); + let value = Value::::new(string.clone()).unwrap(); + let result = value.get_value().unwrap(); + assert_eq!(result, string); + println!("[String] \"{result}\" == \"{string}\" => Passed",); + + /* TODO(FIX): Error with &str + thread 'value::test::metacall_create_value_str' panicked at src/value/mod.rs:96:9: + assertion `left == right` failed + left: "Hello!\"\u{7}" + right: "Hello!" + */ + let str = "Hello!"; + let value = Value::<&str>::new(str).unwrap(); + let result = value.get_value().unwrap(); + assert_eq!(result, str); + println!("[&str] \"{result}\" == \"{str}\" => Passed",); + } + + #[test] + fn metacall_create_value_int() { + let int32 = i32::MAX; + let value = Value::::new(int32).unwrap(); + let result = value.get_value().unwrap(); + assert_eq!(result, int32); + println!("[i32] \"{result}\" == \"{int32}\" => Passed",); + + let int64 = i64::MAX; + let value = Value::::new(int64).unwrap(); + let result = value.get_value().unwrap(); + assert_eq!(result, int64); + println!("[i64] \"{result}\" == \"{int64}\" => Passed",); + } + + #[test] + fn metacall_create_value_float() { + let float32 = f32::MAX; + let value = Value::::new(float32).unwrap(); + let result = value.get_value().unwrap(); + assert_eq!(result, float32); + println!("[i32] \"{result}\" == \"{float32}\" => Passed",); + + let float64 = f64::MAX; + let value = Value::::new(float64).unwrap(); + let result = value.get_value().unwrap(); + assert_eq!(result, float64); + println!("[i64] \"{result}\" == \"{float64}\" => Passed",); + } +} diff --git a/source/ports/rs_port2/src/value/string.rs b/source/ports/rs_port2/src/value/string.rs new file mode 100644 index 000000000..267c97b9b --- /dev/null +++ b/source/ports/rs_port2/src/value/string.rs @@ -0,0 +1,44 @@ +use std::{ffi::CStr, marker::PhantomData}; + +use anyhow::Result; +use metacall_bindings::value::{create::metacall_value_create_string, metacall_value_to_string}; + +use crate::{check_null_ptr, impl_value_constructor}; + +use super::{Value, ValueError}; + +impl Value<&str> { + pub fn get_value(&self) -> Result<&str> { + let ptr = unsafe { metacall_value_to_string(self.ptr) }; + + check_null_ptr!(ptr, ValueError::NullPointer); + + let str = unsafe { CStr::from_ptr(ptr) }.to_str()?; + Ok(str) + } +} + +impl Value { + pub fn get_value(&self) -> Result { + let ptr = unsafe { metacall_value_to_string(self.ptr) }; + + check_null_ptr!(ptr, ValueError::NullPointer); + + let str = unsafe { CStr::from_ptr(ptr) }.to_str()?; + Ok(str.to_string()) + } +} + +impl_value_constructor!( + value => { + let ptr = + unsafe { metacall_value_create_string(value.as_ptr() as *const i8, value.len() ) }; + check_null_ptr!(ptr, ValueError::NullPointer); + Ok(Self { + ptr, + _phantom: PhantomData, + }) + }, + String, + &str +); diff --git a/source/ports/rs_port2/src/value/tests.rs b/source/ports/rs_port2/src/value/tests.rs new file mode 100644 index 000000000..e69de29bb