summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/ffi/00_ffi.js7
-rw-r--r--ext/ffi/dlfcn.rs23
-rw-r--r--ext/ffi/static.rs13
3 files changed, 38 insertions, 5 deletions
diff --git a/ext/ffi/00_ffi.js b/ext/ffi/00_ffi.js
index ea75df65c..a8f05dfca 100644
--- a/ext/ffi/00_ffi.js
+++ b/ext/ffi/00_ffi.js
@@ -443,6 +443,12 @@ class DynamicLibrary {
continue;
}
+ // Symbol was marked as optional, and not found.
+ // In that case, we set its value to null in Rust-side.
+ if (symbols[symbol] === null) {
+ continue;
+ }
+
if (ReflectHas(symbols[symbol], "type")) {
const type = symbols[symbol].type;
if (type === "void") {
@@ -456,6 +462,7 @@ class DynamicLibrary {
this.#rid,
name,
type,
+ symbols[symbol].optional,
);
ObjectDefineProperty(
this.symbols,
diff --git a/ext/ffi/dlfcn.rs b/ext/ffi/dlfcn.rs
index 4f58248e6..3af9177bf 100644
--- a/ext/ffi/dlfcn.rs
+++ b/ext/ffi/dlfcn.rs
@@ -76,12 +76,19 @@ pub struct ForeignFunction {
#[serde(rename = "callback")]
#[serde(default = "default_callback")]
callback: bool,
+ #[serde(rename = "optional")]
+ #[serde(default = "default_optional")]
+ optional: bool,
}
fn default_callback() -> bool {
false
}
+fn default_optional() -> bool {
+ false
+}
+
// ForeignStatic's name and type fields are read and used by
// serde_v8 to determine which variant a ForeignSymbol is.
// They are not used beyond that and are thus marked with underscores.
@@ -156,7 +163,7 @@ where
ForeignSymbol::ForeignStatic(_) => {
// No-op: Statics will be handled separately and are not part of the Rust-side resource.
}
- ForeignSymbol::ForeignFunction(foreign_fn) => {
+ ForeignSymbol::ForeignFunction(foreign_fn) => 'register_symbol: {
let symbol = match &foreign_fn.name {
Some(symbol) => symbol,
None => &symbol_key,
@@ -168,10 +175,18 @@ where
// SAFETY: The obtained T symbol is the size of a pointer.
match unsafe { resource.lib.symbol::<*const c_void>(symbol) } {
Ok(value) => Ok(value),
- Err(err) => Err(generic_error(format!(
- "Failed to register symbol {symbol}: {err}"
- ))),
+ Err(err) => if foreign_fn.optional {
+ let null: v8::Local<v8::Value> = v8::null(scope).into();
+ let func_key = v8::String::new(scope, &symbol_key).unwrap();
+ obj.set(scope, func_key.into(), null);
+ break 'register_symbol;
+ } else {
+ Err(generic_error(format!(
+ "Failed to register symbol {symbol}: {err}"
+ )))
+ },
}?;
+
let ptr = libffi::middle::CodePtr::from_ptr(fn_ptr as _);
let cif = libffi::middle::Cif::new(
foreign_fn
diff --git a/ext/ffi/static.rs b/ext/ffi/static.rs
index 2f32f03fd..ae095d5fc 100644
--- a/ext/ffi/static.rs
+++ b/ext/ffi/static.rs
@@ -20,10 +20,21 @@ pub fn op_ffi_get_static<'scope>(
rid: ResourceId,
name: String,
static_type: NativeType,
+ optional: bool,
) -> Result<serde_v8::Value<'scope>, AnyError> {
let resource = state.resource_table.get::<DynamicLibraryResource>(rid)?;
- let data_ptr = resource.get_static(name)?;
+ let data_ptr = match resource.get_static(name) {
+ Ok(data_ptr) => Ok(data_ptr),
+ Err(err) => {
+ if optional {
+ let null: v8::Local<v8::Value> = v8::null(scope).into();
+ return Ok(null.into());
+ } else {
+ Err(err)
+ }
+ }
+ }?;
Ok(match static_type {
NativeType::Void => {