diff --git a/crates/neon/src/types_impl/extract/json.rs b/crates/neon/src/types_impl/extract/json.rs index 623da2dfb..bfb0a3357 100644 --- a/crates/neon/src/types_impl/extract/json.rs +++ b/crates/neon/src/types_impl/extract/json.rs @@ -23,7 +23,7 @@ use crate::{ result::{JsResult, NeonResult}, types::{ extract::{private, TryFromJs, TryIntoJs}, - JsError, JsFunction, JsObject, JsString, JsValue, + JsError, JsFunction, JsObject, JsValue, }, }; @@ -52,13 +52,6 @@ fn json_stringify<'cx>(cx: &mut Cx<'cx>) -> JsResult<'cx, JsFunction> { .map(|f| f.to_inner(cx)) } -fn stringify(cx: &mut Cx, v: Handle) -> NeonResult { - json_stringify(cx)? - .call(cx, v, [v])? - .downcast_or_throw::(cx) - .map(|s| s.value(cx)) -} - fn global_json_parse<'cx>(cx: &mut Cx<'cx>) -> JsResult<'cx, JsFunction> { cx.global::("JSON")?.get(cx, "parse") } @@ -97,9 +90,14 @@ where cx: &mut Cx<'cx>, v: Handle<'cx, JsValue>, ) -> NeonResult> { - Ok(serde_json::from_str(&stringify(cx, v)?) - .map(Json) - .map_err(Error)) + let s = json_stringify(cx)?.call(cx, v, [v])?; + let res = match String::try_from_js(cx, s)? { + Ok(s) => serde_json::from_str(&s), + // If the type was not a `string`, it must be `undefined` + Err(_) => T::deserialize(serde::de::value::UnitDeserializer::new()), + }; + + Ok(res.map(Json).map_err(Error)) } } diff --git a/test/napi/lib/extract.js b/test/napi/lib/extract.js index 599ee7dce..c469347f5 100644 --- a/test/napi/lib/extract.js +++ b/test/napi/lib/extract.js @@ -73,6 +73,9 @@ describe("Extractors", () => { it("JSON", () => { assert.strictEqual(addon.extract_json_sum([1, 2, 3, 4]), 10); assert.strictEqual(addon.extract_json_sum([8, 16, 18]), 42); + assert.strictEqual(addon.extractJsonOption(42), 42); + assert.strictEqual(addon.extractJsonOption(null), null); + assert.strictEqual(addon.extractJsonOption(), null); }); it("Either", () => { diff --git a/test/napi/src/js/extract.rs b/test/napi/src/js/extract.rs index 9f5741474..fb5893d1e 100644 --- a/test/napi/src/js/extract.rs +++ b/test/napi/src/js/extract.rs @@ -138,6 +138,11 @@ pub fn extract_single_add_one(mut cx: FunctionContext) -> JsResult { Ok(cx.number(n + 1.0)) } +#[neon::export(json)] +pub fn extract_json_option(maybe_x: Option) -> Option { + maybe_x +} + #[neon::export] pub fn extract_either(either: Either) -> String { match either {