diff --git a/packages/web/src/lib.rs b/packages/web/src/lib.rs index 4c0831ef5..a807317f9 100644 --- a/packages/web/src/lib.rs +++ b/packages/web/src/lib.rs @@ -57,7 +57,7 @@ use std::rc::Rc; pub use crate::cfg::Config; -pub use crate::util::use_eval; +pub use crate::util::{use_eval, EvalResult}; use dioxus_core::prelude::Component; use dioxus_core::SchedulerMsg; use dioxus_core::VirtualDom; diff --git a/packages/web/src/util.rs b/packages/web/src/util.rs index b6518b8c7..3ed8bd479 100644 --- a/packages/web/src/util.rs +++ b/packages/web/src/util.rs @@ -1,6 +1,9 @@ //! Utilities specific to websys -use std::str::FromStr; +use std::{ + future::{IntoFuture, Ready}, + str::FromStr, +}; use dioxus_core::*; use serde::de::Error; @@ -19,24 +22,51 @@ use serde_json::Value; /// /// The closure will panic if the provided script is not valid JavaScript code /// or if it returns an uncaught error. -pub fn use_eval( - cx: &ScopeState, -) -> &dyn Fn(S) -> Result { +pub fn use_eval(cx: &ScopeState) -> &dyn Fn(S) -> EvalResult { cx.use_hook(|| { |script: S| { let body = script.to_string(); - if let Ok(value) = - js_sys::Function::new_no_args(&body).call0(&wasm_bindgen::JsValue::NULL) - { - if let Ok(stringified) = js_sys::JSON::stringify(&value) { - let string: String = stringified.into(); - Value::from_str(&string) + EvalResult { + value: if let Ok(value) = + js_sys::Function::new_no_args(&body).call0(&wasm_bindgen::JsValue::NULL) + { + if let Ok(stringified) = js_sys::JSON::stringify(&value) { + if !stringified.is_undefined() && stringified.is_valid_utf16() { + let string: String = stringified.into(); + Value::from_str(&string) + } else { + Err(serde_json::Error::custom("Failed to stringify result")) + } + } else { + Err(serde_json::Error::custom("Failed to stringify result")) + } } else { - Err(serde_json::Error::custom("Failed to stringify result")) - } - } else { - Err(serde_json::Error::custom("Failed to execute script")) + Err(serde_json::Error::custom("Failed to execute script")) + }, } } }) } + +/// A wrapper around the result of a JavaScript evaluation. +/// This implements IntoFuture to be compatible with the desktop renderer's EvalResult. +pub struct EvalResult { + value: Result, +} + +impl EvalResult { + /// Get the result of the Javascript execution. + pub fn get(self) -> Result { + self.value + } +} + +impl IntoFuture for EvalResult { + type Output = Result; + + type IntoFuture = Ready>; + + fn into_future(self) -> Self::IntoFuture { + std::future::ready(self.value) + } +}