diff options
Diffstat (limited to 'ext')
-rw-r--r-- | ext/ffi/00_ffi.js | 7 | ||||
-rw-r--r-- | ext/ffi/dlfcn.rs | 23 | ||||
-rw-r--r-- | ext/ffi/static.rs | 13 |
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 => { |