summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock21
-rw-r--r--ext/ffi/Cargo.toml2
-rw-r--r--ext/ffi/dlfcn.rs76
3 files changed, 97 insertions, 2 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 531c92229..40d06b19d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1065,6 +1065,8 @@ dependencies = [
"dynasmrt",
"libffi",
"serde",
+ "serde-value",
+ "serde_json",
"tokio",
"winapi",
]
@@ -3122,6 +3124,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
+name = "ordered-float"
+version = "2.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
name = "os_pipe"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4013,6 +4024,16 @@ dependencies = [
]
[[package]]
+name = "serde-value"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
+dependencies = [
+ "ordered-float",
+ "serde",
+]
+
+[[package]]
name = "serde_bytes"
version = "0.11.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/ext/ffi/Cargo.toml b/ext/ffi/Cargo.toml
index 2c09ef115..7a48dd034 100644
--- a/ext/ffi/Cargo.toml
+++ b/ext/ffi/Cargo.toml
@@ -19,6 +19,8 @@ dlopen.workspace = true
dynasmrt = "1.2.3"
libffi = "3.1.0"
serde.workspace = true
+serde-value = "0.7"
+serde_json = "1.0"
tokio.workspace = true
[target.'cfg(windows)'.dependencies]
diff --git a/ext/ffi/dlfcn.rs b/ext/ffi/dlfcn.rs
index 570af09fc..c2b123246 100644
--- a/ext/ffi/dlfcn.rs
+++ b/ext/ffi/dlfcn.rs
@@ -15,6 +15,7 @@ use deno_core::Resource;
use deno_core::ResourceId;
use dlopen::raw::Library;
use serde::Deserialize;
+use serde_value::ValueDeserializer;
use std::borrow::Cow;
use std::collections::HashMap;
use std::ffi::c_void;
@@ -97,13 +98,31 @@ struct ForeignStatic {
_type: String,
}
-#[derive(Deserialize, Debug)]
-#[serde(untagged)]
+#[derive(Debug)]
enum ForeignSymbol {
ForeignFunction(ForeignFunction),
ForeignStatic(ForeignStatic),
}
+impl<'de> Deserialize<'de> for ForeignSymbol {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ let value = serde_value::Value::deserialize(deserializer)?;
+
+ // Probe a ForeignStatic and if that doesn't match, assume ForeignFunction to improve error messages
+ if let Ok(res) = ForeignStatic::deserialize(
+ ValueDeserializer::<D::Error>::new(value.clone()),
+ ) {
+ Ok(ForeignSymbol::ForeignStatic(res))
+ } else {
+ ForeignFunction::deserialize(ValueDeserializer::<D::Error>::new(value))
+ .map(ForeignSymbol::ForeignFunction)
+ }
+ }
+}
+
#[derive(Deserialize, Debug)]
pub struct FfiLoadArgs {
path: String,
@@ -395,6 +414,11 @@ pub(crate) fn format_error(e: dlopen::Error, path: String) -> String {
#[cfg(test)]
mod tests {
+ use super::ForeignFunction;
+ use super::ForeignSymbol;
+ use crate::symbol::NativeType;
+ use serde_json::json;
+
#[cfg(target_os = "windows")]
#[test]
fn test_format_error() {
@@ -409,4 +433,52 @@ mod tests {
"foo.dll is not a valid Win32 application.\r\n".to_string(),
);
}
+
+ /// Ensure that our custom serialize for ForeignSymbol is working using `serde_json`.
+ #[test]
+ fn test_serialize_foreign_symbol() {
+ let symbol: ForeignSymbol = serde_json::from_value(json! {{
+ "name": "test",
+ "type": "type is unused"
+ }})
+ .expect("Failed to parse");
+ assert!(matches!(symbol, ForeignSymbol::ForeignStatic(..)));
+
+ let symbol: ForeignSymbol = serde_json::from_value(json! {{
+ "name": "test",
+ "parameters": ["i64"],
+ "result": "bool"
+ }})
+ .expect("Failed to parse");
+ if let ForeignSymbol::ForeignFunction(ForeignFunction {
+ name: Some(expected_name),
+ parameters,
+ ..
+ }) = symbol
+ {
+ assert_eq!(expected_name, "test");
+ assert_eq!(parameters, vec![NativeType::I64]);
+ } else {
+ panic!("Failed to parse ForeignFunction as expected");
+ }
+ }
+
+ #[test]
+ fn test_serialize_foreign_symbol_failures() {
+ let error = serde_json::from_value::<ForeignSymbol>(json! {{
+ "name": "test",
+ "parameters": ["int"],
+ "result": "bool"
+ }})
+ .expect_err("Expected this to fail");
+ assert!(error.to_string().contains("expected one of"));
+
+ let error = serde_json::from_value::<ForeignSymbol>(json! {{
+ "name": "test",
+ "parameters": ["i64"],
+ "result": "int"
+ }})
+ .expect_err("Expected this to fail");
+ assert!(error.to_string().contains("expected one of"));
+ }
}