neon/types_impl/extract/
json.rsuse std::{error, fmt};
use crate::{
context::{Context, Cx},
handle::Handle,
object::Object,
result::{JsResult, NeonResult},
types::{
extract::{private, TryFromJs, TryIntoJs},
JsError, JsFunction, JsObject, JsString, JsValue,
},
};
#[cfg(feature = "napi-6")]
use crate::{handle::Root, thread::LocalKey};
fn global_json_stringify<'cx>(cx: &mut Cx<'cx>) -> JsResult<'cx, JsFunction> {
cx.global::<JsObject>("JSON")?.get(cx, "stringify")
}
#[cfg(not(feature = "napi-6"))]
fn json_stringify<'cx, C>(cx: &mut Cx<'cx>) -> JsResult<'cx, JsFunction> {
global_json_stringify(cx)
}
#[cfg(feature = "napi-6")]
fn json_stringify<'cx>(cx: &mut Cx<'cx>) -> JsResult<'cx, JsFunction> {
static STRINGIFY: LocalKey<Root<JsFunction>> = LocalKey::new();
STRINGIFY
.get_or_try_init(cx, |cx| global_json_stringify(cx).map(|f| f.root(cx)))
.map(|f| f.to_inner(cx))
}
fn stringify(cx: &mut Cx, v: Handle<JsValue>) -> NeonResult<String> {
json_stringify(cx)?
.call(cx, v, [v])?
.downcast_or_throw::<JsString, _>(cx)
.map(|s| s.value(cx))
}
fn global_json_parse<'cx>(cx: &mut Cx<'cx>) -> JsResult<'cx, JsFunction> {
cx.global::<JsObject>("JSON")?.get(cx, "parse")
}
#[cfg(not(feature = "napi-6"))]
fn json_parse<'cx>(cx: &mut Cx<'cx>) -> JsResult<'cx, JsFunction> {
global_json_parse(cx)
}
#[cfg(feature = "napi-6")]
fn json_parse<'cx>(cx: &mut Cx<'cx>) -> JsResult<'cx, JsFunction> {
static PARSE: LocalKey<Root<JsFunction>> = LocalKey::new();
PARSE
.get_or_try_init(cx, |cx| global_json_parse(cx).map(|f| f.root(cx)))
.map(|f| f.to_inner(cx))
}
fn parse<'cx>(cx: &mut Cx<'cx>, s: &str) -> JsResult<'cx, JsValue> {
let s = cx.string(s).upcast();
json_parse(cx)?.call(cx, s, [s])
}
pub struct Json<T>(pub T);
impl<'cx, T> TryFromJs<'cx> for Json<T>
where
for<'de> T: serde::de::Deserialize<'de>,
{
type Error = Error;
fn try_from_js(
cx: &mut Cx<'cx>,
v: Handle<'cx, JsValue>,
) -> NeonResult<Result<Self, Self::Error>> {
Ok(serde_json::from_str(&stringify(cx, v)?)
.map(Json)
.map_err(Error))
}
}
impl<'cx, T> TryIntoJs<'cx> for Json<T>
where
T: serde::Serialize,
{
type Value = JsValue;
fn try_into_js(self, cx: &mut Cx<'cx>) -> JsResult<'cx, Self::Value> {
let s = serde_json::to_string(&self.0).or_else(|err| cx.throw_error(err.to_string()))?;
parse(cx, &s)
}
}
impl<T> private::Sealed for Json<T> {}
pub struct Error(serde_json::Error);
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl error::Error for Error {}
impl<'cx> TryIntoJs<'cx> for Error {
type Value = JsError;
fn try_into_js(self, cx: &mut Cx<'cx>) -> JsResult<'cx, Self::Value> {
JsError::error(cx, self.to_string())
}
}
impl private::Sealed for Error {}