mirror of
https://github.com/denoland/deno.git
synced 2024-12-28 01:59:06 -05:00
ad82918f56
Adds support for passing and returning structs as buffers to FFI. This does not implement fastapi support for structs. Needed for certain system APIs such as AppKit on macOS.
149 lines
5.1 KiB
Rust
149 lines
5.1 KiB
Rust
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
|
|
|
use crate::dlfcn::DynamicLibraryResource;
|
|
use crate::symbol::NativeType;
|
|
use crate::MAX_SAFE_INTEGER;
|
|
use crate::MIN_SAFE_INTEGER;
|
|
use deno_core::error::type_error;
|
|
use deno_core::error::AnyError;
|
|
use deno_core::op;
|
|
use deno_core::serde_v8;
|
|
use deno_core::v8;
|
|
use deno_core::ResourceId;
|
|
use std::ptr;
|
|
|
|
#[op(v8)]
|
|
pub fn op_ffi_get_static<'scope>(
|
|
scope: &mut v8::HandleScope<'scope>,
|
|
state: &mut deno_core::OpState,
|
|
rid: ResourceId,
|
|
name: String,
|
|
static_type: NativeType,
|
|
) -> Result<serde_v8::Value<'scope>, AnyError> {
|
|
let resource = state.resource_table.get::<DynamicLibraryResource>(rid)?;
|
|
|
|
let data_ptr = resource.get_static(name)?;
|
|
|
|
Ok(match static_type {
|
|
NativeType::Void => {
|
|
return Err(type_error("Invalid FFI static type 'void'"));
|
|
}
|
|
NativeType::Bool => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const bool) };
|
|
let boolean: v8::Local<v8::Value> =
|
|
v8::Boolean::new(scope, result).into();
|
|
boolean.into()
|
|
}
|
|
NativeType::U8 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const u8) };
|
|
let number: v8::Local<v8::Value> =
|
|
v8::Integer::new_from_unsigned(scope, result as u32).into();
|
|
number.into()
|
|
}
|
|
NativeType::I8 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const i8) };
|
|
let number: v8::Local<v8::Value> =
|
|
v8::Integer::new(scope, result as i32).into();
|
|
number.into()
|
|
}
|
|
NativeType::U16 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const u16) };
|
|
let number: v8::Local<v8::Value> =
|
|
v8::Integer::new_from_unsigned(scope, result as u32).into();
|
|
number.into()
|
|
}
|
|
NativeType::I16 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const i16) };
|
|
let number: v8::Local<v8::Value> =
|
|
v8::Integer::new(scope, result as i32).into();
|
|
number.into()
|
|
}
|
|
NativeType::U32 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const u32) };
|
|
let number: v8::Local<v8::Value> =
|
|
v8::Integer::new_from_unsigned(scope, result).into();
|
|
number.into()
|
|
}
|
|
NativeType::I32 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const i32) };
|
|
let number: v8::Local<v8::Value> = v8::Integer::new(scope, result).into();
|
|
number.into()
|
|
}
|
|
NativeType::U64 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const u64) };
|
|
let integer: v8::Local<v8::Value> = if result > MAX_SAFE_INTEGER as u64 {
|
|
v8::BigInt::new_from_u64(scope, result).into()
|
|
} else {
|
|
v8::Number::new(scope, result as f64).into()
|
|
};
|
|
integer.into()
|
|
}
|
|
NativeType::I64 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const i64) };
|
|
let integer: v8::Local<v8::Value> = if result > MAX_SAFE_INTEGER as i64
|
|
|| result < MIN_SAFE_INTEGER as i64
|
|
{
|
|
v8::BigInt::new_from_i64(scope, result).into()
|
|
} else {
|
|
v8::Number::new(scope, result as f64).into()
|
|
};
|
|
integer.into()
|
|
}
|
|
NativeType::USize => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const usize) };
|
|
let integer: v8::Local<v8::Value> = if result > MAX_SAFE_INTEGER as usize
|
|
{
|
|
v8::BigInt::new_from_u64(scope, result as u64).into()
|
|
} else {
|
|
v8::Number::new(scope, result as f64).into()
|
|
};
|
|
integer.into()
|
|
}
|
|
NativeType::ISize => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const isize) };
|
|
let integer: v8::Local<v8::Value> =
|
|
if !(MIN_SAFE_INTEGER..=MAX_SAFE_INTEGER).contains(&result) {
|
|
v8::BigInt::new_from_i64(scope, result as i64).into()
|
|
} else {
|
|
v8::Number::new(scope, result as f64).into()
|
|
};
|
|
integer.into()
|
|
}
|
|
NativeType::F32 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const f32) };
|
|
let number: v8::Local<v8::Value> =
|
|
v8::Number::new(scope, result as f64).into();
|
|
number.into()
|
|
}
|
|
NativeType::F64 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const f64) };
|
|
let number: v8::Local<v8::Value> = v8::Number::new(scope, result).into();
|
|
number.into()
|
|
}
|
|
NativeType::Pointer | NativeType::Function | NativeType::Buffer => {
|
|
let result = data_ptr as u64;
|
|
let integer: v8::Local<v8::Value> = if result > MAX_SAFE_INTEGER as u64 {
|
|
v8::BigInt::new_from_u64(scope, result).into()
|
|
} else {
|
|
v8::Number::new(scope, result as f64).into()
|
|
};
|
|
integer.into()
|
|
}
|
|
NativeType::Struct(_) => {
|
|
return Err(type_error("Invalid FFI static type 'struct'"));
|
|
}
|
|
})
|
|
}
|