Skip to content

Commit

Permalink
feat(rs-port2): build the base of the values
Browse files Browse the repository at this point in the history
- implement a constructor and `get_value` for
  - i16, i32, i64
  - f32, f64
  - String, &str
- implement those methods for Value<T>:
  - `is_null()`
  - `value_id()`
  - `value_id_name()`
  • Loading branch information
hulxv committed Nov 25, 2024
1 parent 5203822 commit 8cef261
Show file tree
Hide file tree
Showing 6 changed files with 291 additions and 54 deletions.
54 changes: 0 additions & 54 deletions source/ports/rs_port2/src/value.rs

This file was deleted.

51 changes: 51 additions & 0 deletions source/ports/rs_port2/src/value/float.rs
Original file line number Diff line number Diff line change
@@ -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<f32> {
pub fn get_value(&self) -> Result<f32> {
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<f64> {
pub fn get_value(&self) -> Result<f64> {
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
);
61 changes: 61 additions & 0 deletions source/ports/rs_port2/src/value/int.rs
Original file line number Diff line number Diff line change
@@ -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<i64> {
pub fn get_value(&self) -> Result<i64> {
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<i32> {
pub fn get_value(&self) -> Result<i32> {
let res = unsafe { metacall_value_to_int(self.ptr).to_owned() };

Ok(res)
}
}

impl Value<i16> {
pub fn get_value(&self) -> Result<i16> {
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
);
135 changes: 135 additions & 0 deletions source/ports/rs_port2/src/value/mod.rs
Original file line number Diff line number Diff line change
@@ -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<Self> {
$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<T> {
ptr: *mut c_void,
_phantom: PhantomData<T>,
}

impl<T> Value<T> {
/// A simple method to check the nullity of the Value.
pub fn is_null(&self) -> Result<bool> {
let id = self.value_id()?;
Ok(id == MetacallValueID::Null)
}

/// Provides the type identifier (ID).
pub fn value_id(&self) -> Result<MetacallValueID> {
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<String> {
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<T> Drop for Value<T> {
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::<String>::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::<i32>::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::<i64>::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::<f32>::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::<f64>::new(float64).unwrap();
let result = value.get_value().unwrap();
assert_eq!(result, float64);
println!("[i64] \"{result}\" == \"{float64}\" => Passed",);
}
}
44 changes: 44 additions & 0 deletions source/ports/rs_port2/src/value/string.rs
Original file line number Diff line number Diff line change
@@ -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<String> {
pub fn get_value(&self) -> Result<String> {
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
);
Empty file.

0 comments on commit 8cef261

Please sign in to comment.