neon/types_impl/extract/
json.rs1use std::{error, fmt};
18
19use crate::{
20 context::{Context, Cx},
21 handle::Handle,
22 object::Object,
23 result::{JsResult, NeonResult},
24 types::{
25 extract::{private, TryFromJs, TryIntoJs},
26 JsError, JsFunction, JsObject, JsValue,
27 },
28};
29
30#[cfg(feature = "napi-6")]
31use crate::{handle::Root, thread::LocalKey};
32
33fn global_json_stringify<'cx>(cx: &mut Cx<'cx>) -> JsResult<'cx, JsFunction> {
34 cx.global::<JsObject>("JSON")?.get(cx, "stringify")
35}
36
37#[cfg(not(feature = "napi-6"))]
38fn json_stringify<'cx>(cx: &mut Cx<'cx>) -> JsResult<'cx, JsFunction> {
43 global_json_stringify(cx)
44}
45
46#[cfg(feature = "napi-6")]
47fn json_stringify<'cx>(cx: &mut Cx<'cx>) -> JsResult<'cx, JsFunction> {
48 static STRINGIFY: LocalKey<Root<JsFunction>> = LocalKey::new();
49
50 STRINGIFY
51 .get_or_try_init(cx, |cx| global_json_stringify(cx).map(|f| f.root(cx)))
52 .map(|f| f.to_inner(cx))
53}
54
55fn global_json_parse<'cx>(cx: &mut Cx<'cx>) -> JsResult<'cx, JsFunction> {
56 cx.global::<JsObject>("JSON")?.get(cx, "parse")
57}
58
59#[cfg(not(feature = "napi-6"))]
60fn json_parse<'cx>(cx: &mut Cx<'cx>) -> JsResult<'cx, JsFunction> {
61 global_json_parse(cx)
62}
63
64#[cfg(feature = "napi-6")]
65fn json_parse<'cx>(cx: &mut Cx<'cx>) -> JsResult<'cx, JsFunction> {
66 static PARSE: LocalKey<Root<JsFunction>> = LocalKey::new();
67
68 PARSE
69 .get_or_try_init(cx, |cx| global_json_parse(cx).map(|f| f.root(cx)))
70 .map(|f| f.to_inner(cx))
71}
72
73fn parse<'cx>(cx: &mut Cx<'cx>, s: &str) -> JsResult<'cx, JsValue> {
74 let s = cx.string(s).upcast();
75
76 json_parse(cx)?.call(cx, s, [s])
77}
78
79pub struct Json<T>(pub T);
82
83impl<'cx, T> TryFromJs<'cx> for Json<T>
84where
85 for<'de> T: serde::de::Deserialize<'de>,
86{
87 type Error = Error;
88
89 fn try_from_js(
90 cx: &mut Cx<'cx>,
91 v: Handle<'cx, JsValue>,
92 ) -> NeonResult<Result<Self, Self::Error>> {
93 let s = json_stringify(cx)?.call(cx, v, [v])?;
94 let res = match String::try_from_js(cx, s)? {
95 Ok(s) => serde_json::from_str(&s),
96 Err(_) => T::deserialize(serde::de::value::UnitDeserializer::new()),
98 };
99
100 Ok(res.map(Json).map_err(Error))
101 }
102}
103
104impl<'cx, T> TryIntoJs<'cx> for Json<T>
105where
106 T: serde::Serialize,
107{
108 type Value = JsValue;
109
110 fn try_into_js(self, cx: &mut Cx<'cx>) -> JsResult<'cx, Self::Value> {
111 TryIntoJs::try_into_js(&self, cx)
112 }
113}
114
115impl<'cx, T> TryIntoJs<'cx> for &Json<T>
116where
117 T: serde::Serialize,
118{
119 type Value = JsValue;
120
121 fn try_into_js(self, cx: &mut Cx<'cx>) -> JsResult<'cx, Self::Value> {
122 let s = serde_json::to_string(&self.0).or_else(|err| cx.throw_error(err.to_string()))?;
123
124 parse(cx, &s)
125 }
126}
127
128impl<T> private::Sealed for Json<T> {}
129
130impl<T> private::Sealed for &Json<T> {}
131
132pub struct Error(serde_json::Error);
134
135impl fmt::Display for Error {
136 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137 fmt::Display::fmt(&self.0, f)
138 }
139}
140
141impl fmt::Debug for Error {
142 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143 fmt::Debug::fmt(&self.0, f)
144 }
145}
146
147impl error::Error for Error {}
148
149impl<'cx> TryIntoJs<'cx> for Error {
150 type Value = JsError;
151
152 fn try_into_js(self, cx: &mut Cx<'cx>) -> JsResult<'cx, Self::Value> {
153 JsError::error(cx, self.to_string())
154 }
155}
156
157impl private::Sealed for Error {}