summaryrefslogtreecommitdiff
path: root/ext/ffi/lib.rs
diff options
context:
space:
mode:
authorElias Sjögreen <eliassjogreen1@gmail.com>2022-06-08 13:13:10 +0200
committerGitHub <noreply@github.com>2022-06-08 16:43:10 +0530
commit8113fac939c06b0d71a22d008c060bed3cb47d72 (patch)
treecd9734046f414b344d4b8000c125f8b682768177 /ext/ffi/lib.rs
parent2769d602506af1953312b28580506fca3fcbe030 (diff)
feat(ext/ffi): support passing and returning bigints (#14523)
Diffstat (limited to 'ext/ffi/lib.rs')
-rw-r--r--ext/ffi/lib.rs45
1 files changed, 41 insertions, 4 deletions
diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs
index 01aa17698..8a1a75b1d 100644
--- a/ext/ffi/lib.rs
+++ b/ext/ffi/lib.rs
@@ -311,6 +311,11 @@ impl NativeValue {
}
fn value_as_uint<T: TryFrom<u64>>(value: Value) -> Result<T, AnyError> {
+ if value.is_array() {
+ let value = U32x2::try_from(value)?;
+ return T::try_from(u64::from(value)).map_err(|_| type_error(format!("Found U32x2 FFI argument but it could not be converted to an unsigned integer, got {:?}", value)));
+ }
+
match value.as_u64().and_then(|v| T::try_from(v).ok()) {
Some(value) => Ok(value),
None => Err(type_error(format!(
@@ -321,6 +326,11 @@ fn value_as_uint<T: TryFrom<u64>>(value: Value) -> Result<T, AnyError> {
}
fn value_as_int<T: TryFrom<i64>>(value: Value) -> Result<T, AnyError> {
+ if value.is_array() {
+ let value = U32x2::try_from(value)?;
+ return T::try_from(u64::from(value) as i64).map_err(|_| type_error(format!("Found U32x2 FFI argument but it could not be converted to a signed integer, got {:?}", value)));
+ }
+
match value.as_i64().and_then(|v| T::try_from(v).ok()) {
Some(value) => Ok(value),
None => Err(type_error(format!(
@@ -359,6 +369,25 @@ impl From<U32x2> for u64 {
}
}
+impl TryFrom<Value> for U32x2 {
+ type Error = AnyError;
+
+ fn try_from(value: Value) -> Result<Self, Self::Error> {
+ if let Some(value) = value.as_array() {
+ if let Some(hi) = value[0].as_u64() {
+ if let Some(lo) = value[1].as_u64() {
+ return Ok(U32x2(hi as u32, lo as u32));
+ }
+ }
+ }
+
+ Err(type_error(format!(
+ "Expected FFI argument to be a signed integer, but got {:?}",
+ value
+ )))
+ }
+}
+
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct ForeignFunction {
@@ -627,16 +656,24 @@ fn ffi_call(args: FfiCallArgs, symbol: &Symbol) -> Result<Value, AnyError> {
json!(unsafe { symbol.cif.call::<i32>(symbol.ptr, &call_args) })
}
NativeType::U64 => {
- json!(unsafe { symbol.cif.call::<u64>(symbol.ptr, &call_args) })
+ json!(U32x2::from(unsafe {
+ symbol.cif.call::<u64>(symbol.ptr, &call_args)
+ }))
}
NativeType::I64 => {
- json!(unsafe { symbol.cif.call::<i64>(symbol.ptr, &call_args) })
+ json!(U32x2::from(unsafe {
+ symbol.cif.call::<i64>(symbol.ptr, &call_args)
+ } as u64))
}
NativeType::USize => {
- json!(unsafe { symbol.cif.call::<usize>(symbol.ptr, &call_args) })
+ json!(U32x2::from(unsafe {
+ symbol.cif.call::<usize>(symbol.ptr, &call_args)
+ } as u64))
}
NativeType::ISize => {
- json!(unsafe { symbol.cif.call::<isize>(symbol.ptr, &call_args) })
+ json!(U32x2::from(unsafe {
+ symbol.cif.call::<isize>(symbol.ptr, &call_args)
+ } as u64))
}
NativeType::F32 => {
json!(unsafe { symbol.cif.call::<f32>(symbol.ptr, &call_args) })