summaryrefslogtreecommitdiff
path: root/extensions/ffi/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/ffi/lib.rs')
-rw-r--r--extensions/ffi/lib.rs397
1 files changed, 0 insertions, 397 deletions
diff --git a/extensions/ffi/lib.rs b/extensions/ffi/lib.rs
deleted file mode 100644
index 125e6da99..000000000
--- a/extensions/ffi/lib.rs
+++ /dev/null
@@ -1,397 +0,0 @@
-// Copyright 2021 the Deno authors. All rights reserved. MIT license.
-
-use deno_core::error::bad_resource_id;
-use deno_core::error::AnyError;
-use deno_core::include_js_files;
-use deno_core::op_sync;
-use deno_core::serde_json::json;
-use deno_core::serde_json::Value;
-use deno_core::Extension;
-use deno_core::OpState;
-use deno_core::Resource;
-use deno_core::ResourceId;
-use dlopen::raw::Library;
-use libffi::middle::Arg;
-use serde::Deserialize;
-use std::borrow::Cow;
-use std::collections::HashMap;
-use std::convert::TryFrom;
-use std::ffi::c_void;
-use std::rc::Rc;
-
-pub struct Unstable(pub bool);
-
-fn check_unstable(state: &OpState, api_name: &str) {
- let unstable = state.borrow::<Unstable>();
-
- if !unstable.0 {
- eprintln!(
- "Unstable API '{}'. The --unstable flag must be provided.",
- api_name
- );
- std::process::exit(70);
- }
-}
-
-pub trait FfiPermissions {
- fn check(&mut self, path: &str) -> Result<(), AnyError>;
-}
-
-pub struct NoFfiPermissions;
-
-impl FfiPermissions for NoFfiPermissions {
- fn check(&mut self, _path: &str) -> Result<(), AnyError> {
- Ok(())
- }
-}
-
-struct Symbol {
- cif: libffi::middle::Cif,
- ptr: libffi::middle::CodePtr,
- parameter_types: Vec<NativeType>,
- result_type: NativeType,
-}
-
-struct DynamicLibraryResource {
- lib: Library,
- symbols: HashMap<String, Symbol>,
-}
-
-impl Resource for DynamicLibraryResource {
- fn name(&self) -> Cow<str> {
- "dynamicLibrary".into()
- }
-
- fn close(self: Rc<Self>) {
- drop(self)
- }
-}
-
-impl DynamicLibraryResource {
- fn register(
- &mut self,
- symbol: String,
- foreign_fn: ForeignFunction,
- ) -> Result<(), AnyError> {
- let fn_ptr = unsafe { self.lib.symbol::<*const c_void>(&symbol) }?;
- let ptr = libffi::middle::CodePtr::from_ptr(fn_ptr as _);
- let parameter_types =
- foreign_fn.parameters.into_iter().map(NativeType::from);
- let result_type = NativeType::from(foreign_fn.result);
- let cif = libffi::middle::Cif::new(
- parameter_types.clone().map(libffi::middle::Type::from),
- result_type.into(),
- );
-
- self.symbols.insert(
- symbol,
- Symbol {
- cif,
- ptr,
- parameter_types: parameter_types.collect(),
- result_type,
- },
- );
-
- Ok(())
- }
-}
-
-pub fn init<P: FfiPermissions + 'static>(unstable: bool) -> Extension {
- Extension::builder()
- .js(include_js_files!(
- prefix "deno:extensions/ffi",
- "00_ffi.js",
- ))
- .ops(vec![
- ("op_ffi_load", op_sync(op_ffi_load::<P>)),
- ("op_ffi_call", op_sync(op_ffi_call)),
- ])
- .state(move |state| {
- // Stolen from deno_webgpu, is there a better option?
- state.put(Unstable(unstable));
- Ok(())
- })
- .build()
-}
-
-#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
-#[serde(rename_all = "lowercase")]
-enum NativeType {
- Void,
- U8,
- I8,
- U16,
- I16,
- U32,
- I32,
- U64,
- I64,
- USize,
- ISize,
- F32,
- F64,
-}
-
-impl From<NativeType> for libffi::middle::Type {
- fn from(native_type: NativeType) -> Self {
- match native_type {
- NativeType::Void => libffi::middle::Type::void(),
- NativeType::U8 => libffi::middle::Type::u8(),
- NativeType::I8 => libffi::middle::Type::i8(),
- NativeType::U16 => libffi::middle::Type::u16(),
- NativeType::I16 => libffi::middle::Type::i16(),
- NativeType::U32 => libffi::middle::Type::u32(),
- NativeType::I32 => libffi::middle::Type::i32(),
- NativeType::U64 => libffi::middle::Type::u64(),
- NativeType::I64 => libffi::middle::Type::i64(),
- NativeType::USize => libffi::middle::Type::usize(),
- NativeType::ISize => libffi::middle::Type::isize(),
- NativeType::F32 => libffi::middle::Type::f32(),
- NativeType::F64 => libffi::middle::Type::f64(),
- }
- }
-}
-
-impl From<String> for NativeType {
- fn from(string: String) -> Self {
- match string.as_str() {
- "void" => NativeType::Void,
- "u8" => NativeType::U8,
- "i8" => NativeType::I8,
- "u16" => NativeType::U16,
- "i16" => NativeType::I16,
- "u32" => NativeType::U32,
- "i32" => NativeType::I32,
- "u64" => NativeType::U64,
- "i64" => NativeType::I64,
- "usize" => NativeType::USize,
- "isize" => NativeType::ISize,
- "f32" => NativeType::F32,
- "f64" => NativeType::F64,
- _ => unimplemented!(),
- }
- }
-}
-
-#[repr(C)]
-union NativeValue {
- void_value: (),
- u8_value: u8,
- i8_value: i8,
- u16_value: u16,
- i16_value: i16,
- u32_value: u32,
- i32_value: i32,
- u64_value: u64,
- i64_value: i64,
- usize_value: usize,
- isize_value: isize,
- f32_value: f32,
- f64_value: f64,
-}
-
-impl NativeValue {
- fn new(native_type: NativeType, value: Value) -> Self {
- match native_type {
- NativeType::Void => Self { void_value: () },
- NativeType::U8 => Self {
- u8_value: value_as_uint::<u8>(value),
- },
- NativeType::I8 => Self {
- i8_value: value_as_int::<i8>(value),
- },
- NativeType::U16 => Self {
- u16_value: value_as_uint::<u16>(value),
- },
- NativeType::I16 => Self {
- i16_value: value_as_int::<i16>(value),
- },
- NativeType::U32 => Self {
- u32_value: value_as_uint::<u32>(value),
- },
- NativeType::I32 => Self {
- i32_value: value_as_int::<i32>(value),
- },
- NativeType::U64 => Self {
- u64_value: value_as_uint::<u64>(value),
- },
- NativeType::I64 => Self {
- i64_value: value_as_int::<i64>(value),
- },
- NativeType::USize => Self {
- usize_value: value_as_uint::<usize>(value),
- },
- NativeType::ISize => Self {
- isize_value: value_as_int::<isize>(value),
- },
- NativeType::F32 => Self {
- f32_value: value_as_f32(value),
- },
- NativeType::F64 => Self {
- f64_value: value_as_f64(value),
- },
- }
- }
-
- unsafe fn as_arg(&self, native_type: NativeType) -> Arg {
- match native_type {
- NativeType::Void => Arg::new(&self.void_value),
- NativeType::U8 => Arg::new(&self.u8_value),
- NativeType::I8 => Arg::new(&self.i8_value),
- NativeType::U16 => Arg::new(&self.u16_value),
- NativeType::I16 => Arg::new(&self.i16_value),
- NativeType::U32 => Arg::new(&self.u32_value),
- NativeType::I32 => Arg::new(&self.i32_value),
- NativeType::U64 => Arg::new(&self.u64_value),
- NativeType::I64 => Arg::new(&self.i64_value),
- NativeType::USize => Arg::new(&self.usize_value),
- NativeType::ISize => Arg::new(&self.isize_value),
- NativeType::F32 => Arg::new(&self.f32_value),
- NativeType::F64 => Arg::new(&self.f64_value),
- }
- }
-}
-
-fn value_as_uint<T: TryFrom<u64>>(value: Value) -> T {
- value
- .as_u64()
- .and_then(|v| T::try_from(v).ok())
- .expect("Expected ffi arg value to be an unsigned integer")
-}
-
-fn value_as_int<T: TryFrom<i64>>(value: Value) -> T {
- value
- .as_i64()
- .and_then(|v| T::try_from(v).ok())
- .expect("Expected ffi arg value to be a signed integer")
-}
-
-fn value_as_f32(value: Value) -> f32 {
- value_as_f64(value) as f32
-}
-
-fn value_as_f64(value: Value) -> f64 {
- value
- .as_f64()
- .expect("Expected ffi arg value to be a float")
-}
-
-#[derive(Deserialize, Debug)]
-struct ForeignFunction {
- parameters: Vec<String>,
- result: String,
-}
-
-#[derive(Deserialize, Debug)]
-struct FfiLoadArgs {
- path: String,
- symbols: HashMap<String, ForeignFunction>,
-}
-
-fn op_ffi_load<FP>(
- state: &mut deno_core::OpState,
- args: FfiLoadArgs,
- _: (),
-) -> Result<ResourceId, AnyError>
-where
- FP: FfiPermissions + 'static,
-{
- check_unstable(state, "Deno.dlopen");
- let permissions = state.borrow_mut::<FP>();
- permissions.check(&args.path)?;
-
- let lib = Library::open(args.path)?;
- let mut resource = DynamicLibraryResource {
- lib,
- symbols: HashMap::new(),
- };
-
- for (symbol, foreign_fn) in args.symbols {
- resource.register(symbol, foreign_fn)?;
- }
-
- Ok(state.resource_table.add(resource))
-}
-
-#[derive(Deserialize, Debug)]
-#[serde(rename_all = "camelCase")]
-struct FfiCallArgs {
- rid: ResourceId,
- symbol: String,
- parameters: Vec<Value>,
-}
-
-fn op_ffi_call(
- state: &mut deno_core::OpState,
- args: FfiCallArgs,
- _: (),
-) -> Result<Value, AnyError> {
- let resource = state
- .resource_table
- .get::<DynamicLibraryResource>(args.rid)
- .ok_or_else(bad_resource_id)?;
-
- let symbol = resource
- .symbols
- .get(&args.symbol)
- .ok_or_else(bad_resource_id)?;
-
- let native_values = symbol
- .parameter_types
- .iter()
- .zip(args.parameters.into_iter())
- .map(|(&native_type, value)| NativeValue::new(native_type, value))
- .collect::<Vec<_>>();
-
- let call_args = symbol
- .parameter_types
- .iter()
- .zip(native_values.iter())
- .map(|(&native_type, native_value)| unsafe {
- native_value.as_arg(native_type)
- })
- .collect::<Vec<_>>();
-
- Ok(match symbol.result_type {
- NativeType::Void => {
- json!(unsafe { symbol.cif.call::<()>(symbol.ptr, &call_args) })
- }
- NativeType::U8 => {
- json!(unsafe { symbol.cif.call::<u8>(symbol.ptr, &call_args) })
- }
- NativeType::I8 => {
- json!(unsafe { symbol.cif.call::<i8>(symbol.ptr, &call_args) })
- }
- NativeType::U16 => {
- json!(unsafe { symbol.cif.call::<u16>(symbol.ptr, &call_args) })
- }
- NativeType::I16 => {
- json!(unsafe { symbol.cif.call::<i16>(symbol.ptr, &call_args) })
- }
- NativeType::U32 => {
- json!(unsafe { symbol.cif.call::<u32>(symbol.ptr, &call_args) })
- }
- NativeType::I32 => {
- json!(unsafe { symbol.cif.call::<i32>(symbol.ptr, &call_args) })
- }
- NativeType::U64 => {
- json!(unsafe { symbol.cif.call::<u64>(symbol.ptr, &call_args) })
- }
- NativeType::I64 => {
- json!(unsafe { symbol.cif.call::<i64>(symbol.ptr, &call_args) })
- }
- NativeType::USize => {
- json!(unsafe { symbol.cif.call::<usize>(symbol.ptr, &call_args) })
- }
- NativeType::ISize => {
- json!(unsafe { symbol.cif.call::<isize>(symbol.ptr, &call_args) })
- }
- NativeType::F32 => {
- json!(unsafe { symbol.cif.call::<f32>(symbol.ptr, &call_args) })
- }
- NativeType::F64 => {
- json!(unsafe { symbol.cif.call::<f64>(symbol.ptr, &call_args) })
- }
- })
-}