1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![doc = include_str!("../README.md")]
3
4use std::{error::Error, fmt::Display, sync::Arc};
5
6#[cfg(feature = "build")]
7mod build;
8#[cfg(feature = "build")]
9pub use build::*;
10
11pub use dioxus_use_js_macro::use_js;
12
13#[doc(hidden)]
16pub use serde::Serialize as SerdeSerialize;
17#[doc(hidden)]
18pub use serde::de::DeserializeOwned as SerdeDeDeserializeOwned;
19#[doc(hidden)]
20pub use serde::de::Error as SerdeDeError;
21#[doc(hidden)]
22pub use serde_json::Error as SerdeJsonError;
23#[doc(hidden)]
24pub use serde_json::Value as SerdeJsonValue;
25#[doc(hidden)]
26pub use serde_json::from_value as serde_json_from_value;
27#[doc(hidden)]
28pub const __SEND_VALIDATION_MSG: &str = "Should always send back a value that is an array of two.";
29#[doc(hidden)]
30pub const __INDEX_VALIDATION_MSG: &str = "The first sent back value should always be a u64.";
31#[doc(hidden)]
32pub const __BAD_CALL_MSG: &str = "Should only attempt to call known actions.";
33#[doc(hidden)]
34pub const __BAD_VOID_RETURN: &str =
35 "A function that should return no value instead returned a value";
36fn _send_sync_error_assert() {
44 fn is_send<T: Send>(_: &T) {}
45 fn is_sync<T: Sync>(_: &T) {}
46 fn is_error<T: Error>(_: &T) {}
47
48 let o: JsError = JsError::Callback {
49 func: "",
50 callback: "",
51 error: Box::new(std::io::Error::new(std::io::ErrorKind::Other, ""))
52 as Box<dyn Error + Send + Sync>,
53 };
54 is_send(&o);
55 is_sync(&o);
56 is_error(&o);
57}
58
59#[derive(Debug)]
61pub enum JsError {
62 Eval {
66 func: &'static str,
68 error: dioxus::document::EvalError,
69 },
70 Threw {
72 func: &'static str,
74 },
75 Callback {
77 func: &'static str,
79 callback: &'static str,
81 error: Box<dyn Error + Send + Sync>,
83 },
84}
85
86impl std::fmt::Display for JsError {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 match self {
89 JsError::Eval { func: name, error } => {
90 write!(f, "JavaScript function '{}' eval error: {}", name, error)
91 }
92 JsError::Threw { func: name } => {
93 write!(
94 f,
95 "JavaScript function '{}' threw an error during execution",
96 name
97 )
98 }
99 JsError::Callback {
100 func: name,
101 callback,
102 error,
103 } => {
104 write!(
105 f,
106 "JavaScript function '{}' callback '{}' error: {}",
107 name, callback, error
108 )
109 }
110 }
111 }
112}
113
114impl std::error::Error for JsError {}
115
116#[derive(
133 serde::Serialize, serde::Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash,
134)]
135pub struct JsValue(Arc<Inner>);
136
137#[derive(
139 serde::Serialize, serde::Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash,
140)]
141struct Inner(String);
142
143impl JsValue {
144 #[deprecated(note = "This constructor is for internal use only. Do not use directly.")]
145 #[doc(hidden)]
146 pub fn internal_create(id: String) -> Self {
147 Self(Arc::new(Inner(id)))
148 }
149
150 #[deprecated(note = "This is for internal use only. Do not use directly.")]
151 #[doc(hidden)]
152 pub fn internal_get(&self) -> &str {
153 self.0.0.as_str()
154 }
155}
156
157impl Display for JsValue {
158 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159 write!(f, "Value in js: window[\"{}\"]", self.0.0)
160 }
161}
162
163impl Drop for Inner {
164 fn drop(&mut self) {
165 let object_name = std::mem::take(&mut self.0);
166 dioxus::core::spawn_forever(async move {
168 let eval = dioxus::document::eval(
169 r#"
170const objectName = await dioxus.recv();
171delete window[objectName];
172return null;
173"#,
174 );
175 if let Err(error) = eval.send(object_name.as_str()) {
176 dioxus::logger::tracing::error!(
177 "Failed to send object name to clean up `window[\"{object_name}\"]`. Error: {error}"
178 );
179 }
180 if let Err(error) = eval.await {
181 dioxus::logger::tracing::error!(
182 "Failed to clean up JavaScript object `window[\"{object_name}\"]`. Error: {error}"
183 );
184 } else {
185 dioxus::logger::tracing::trace!(
186 "Successfully dropped JsValue and cleaned up JavaScript object `window[\"{object_name}\"]`."
187 );
188 }
189 });
190 }
191}