Răsfoiți Sursa

Eval should never return an error

Only awaiting eval should error.
Eval should always be available, even if using its methods returns errors.
Jonathan Kelley 1 an în urmă
părinte
comite
cbadea022a

+ 1 - 2
examples/eval.rs

@@ -25,8 +25,7 @@ fn app() -> Element {
                 console.log(msg);
                 return "hi from JS!";
             "#,
-        )
-        .unwrap();
+        );
 
         // Send a message to the JS code.
         eval.send("Hi from Rust!".into()).unwrap();

+ 1 - 1
packages/desktop/headless_tests/events.rs

@@ -45,7 +45,7 @@ fn mock_event(id: &'static str, value: &'static str) {
                 value, id
             );
 
-            eval(&js).unwrap().await.unwrap();
+            eval(&js).await.unwrap();
         });
     })
 }

+ 0 - 1
packages/desktop/headless_tests/rendering.rs

@@ -38,7 +38,6 @@ fn use_inner_html(id: &'static str) -> Option<String> {
                     return element.innerHTML"#,
                 id
             ))
-            .unwrap()
             .await
             .unwrap();
 

+ 2 - 2
packages/desktop/src/eval.rs

@@ -15,8 +15,8 @@ impl DesktopEvalProvider {
 }
 
 impl EvalProvider for DesktopEvalProvider {
-    fn new_evaluator(&self, js: String) -> Result<GenerationalBox<Box<dyn Evaluator>>, EvalError> {
-        Ok(DesktopEvaluator::create(self.desktop_ctx.clone(), js))
+    fn new_evaluator(&self, js: String) -> GenerationalBox<Box<dyn Evaluator>> {
+        DesktopEvaluator::create(self.desktop_ctx.clone(), js)
     }
 }
 

+ 40 - 14
packages/html/src/eval.rs

@@ -1,7 +1,7 @@
 #![allow(clippy::await_holding_refcell_ref)]
 
 use dioxus_core::prelude::*;
-use generational_box::GenerationalBox;
+use generational_box::{AnyStorage, GenerationalBox, UnsyncStorage};
 use std::future::{poll_fn, Future, IntoFuture};
 use std::pin::Pin;
 use std::rc::Rc;
@@ -10,7 +10,7 @@ use std::task::{Context, Poll};
 /// A struct that implements EvalProvider is sent through [`ScopeState`]'s provide_context function
 /// so that [`use_eval`] can provide a platform agnostic interface for evaluating JavaScript code.
 pub trait EvalProvider {
-    fn new_evaluator(&self, js: String) -> Result<GenerationalBox<Box<dyn Evaluator>>, EvalError>;
+    fn new_evaluator(&self, js: String) -> GenerationalBox<Box<dyn Evaluator>>;
 }
 
 /// The platform's evaluator.
@@ -29,7 +29,7 @@ pub trait Evaluator {
     ) -> Poll<Result<serde_json::Value, EvalError>>;
 }
 
-type EvalCreator = Rc<dyn Fn(&str) -> Result<UseEval, EvalError>>;
+type EvalCreator = Rc<dyn Fn(&str) -> UseEval>;
 
 /// Get a struct that can execute any JavaScript.
 ///
@@ -43,19 +43,45 @@ type EvalCreator = Rc<dyn Fn(&str) -> Result<UseEval, EvalError>>;
 pub fn eval_provider() -> EvalCreator {
     let eval_provider = consume_context::<Rc<dyn EvalProvider>>();
 
-    Rc::new(move |script: &str| {
-        eval_provider
-            .new_evaluator(script.to_string())
-            .map(UseEval::new)
-    }) as Rc<dyn Fn(&str) -> Result<UseEval, EvalError>>
+    Rc::new(move |script: &str| UseEval::new(eval_provider.new_evaluator(script.to_string())))
+        as Rc<dyn Fn(&str) -> UseEval>
 }
 
-pub fn eval(script: &str) -> Result<UseEval, EvalError> {
-    let eval_provider = dioxus_core::prelude::consume_context::<Rc<dyn EvalProvider>>();
-
-    eval_provider
-        .new_evaluator(script.to_string())
-        .map(UseEval::new)
+pub fn eval(script: &str) -> UseEval {
+    let eval_provider = dioxus_core::prelude::try_consume_context::<Rc<dyn EvalProvider>>()
+        // Create a dummy provider that always hiccups when trying to evaluate
+        // That way, we can still compile and run the code without a real provider
+        .unwrap_or_else(|| {
+            struct DummyProvider;
+            impl EvalProvider for DummyProvider {
+                fn new_evaluator(&self, _js: String) -> GenerationalBox<Box<dyn Evaluator>> {
+                    UnsyncStorage::owner().insert(Box::new(DummyEvaluator))
+                }
+            }
+
+            struct DummyEvaluator;
+            impl Evaluator for DummyEvaluator {
+                fn send(&self, _data: serde_json::Value) -> Result<(), EvalError> {
+                    Err(EvalError::Unsupported)
+                }
+                fn poll_recv(
+                    &mut self,
+                    _context: &mut Context<'_>,
+                ) -> Poll<Result<serde_json::Value, EvalError>> {
+                    Poll::Ready(Err(EvalError::Unsupported))
+                }
+                fn poll_join(
+                    &mut self,
+                    _context: &mut Context<'_>,
+                ) -> Poll<Result<serde_json::Value, EvalError>> {
+                    Poll::Ready(Err(EvalError::Unsupported))
+                }
+            }
+
+            Rc::new(DummyProvider) as Rc<dyn EvalProvider>
+        });
+
+    UseEval::new(eval_provider.new_evaluator(script.to_string()))
 }
 
 /// A wrapper around the target platform's evaluator.

+ 2 - 2
packages/liveview/src/eval.rs

@@ -18,8 +18,8 @@ pub struct DesktopEvalProvider {
 }
 
 impl EvalProvider for DesktopEvalProvider {
-    fn new_evaluator(&self, js: String) -> Result<GenerationalBox<Box<dyn Evaluator>>, EvalError> {
-        Ok(DesktopEvaluator::create(self.query.clone(), js))
+    fn new_evaluator(&self, js: String) -> GenerationalBox<Box<dyn Evaluator>> {
+        DesktopEvaluator::create(self.query.clone(), js)
     }
 }
 

+ 5 - 6
packages/playwright-tests/web/src/main.rs

@@ -24,12 +24,11 @@ fn app() -> Element {
             class: "eval-button",
             onclick: move |_| async move {
                 let mut eval = eval(
-                        r#"
-                            window.document.title = 'Hello from Dioxus Eval!';
-                            dioxus.send("returned eval value");
-                        "#,
-                    )
-                    .unwrap();
+                    r#"
+                        window.document.title = 'Hello from Dioxus Eval!';
+                        dioxus.send("returned eval value");
+                    "#,
+                );
 
                 let result = eval.recv().await;
                 if let Ok(serde_json::Value::String(string)) = result {

+ 2 - 2
packages/ssr/src/eval.rs

@@ -13,9 +13,9 @@ pub fn init_eval() {
 /// Reprents the ssr-target's provider of evaluators.
 pub struct SSREvalProvider;
 impl EvalProvider for SSREvalProvider {
-    fn new_evaluator(&self, _: String) -> Result<GenerationalBox<Box<dyn Evaluator>>, EvalError> {
+    fn new_evaluator(&self, _: String) -> GenerationalBox<Box<dyn Evaluator>> {
         let owner = UnsyncStorage::owner();
-        Ok(owner.insert(Box::new(SSREvaluator) as Box<dyn Evaluator + 'static>))
+        owner.insert(Box::new(SSREvaluator) as Box<dyn Evaluator + 'static>)
     }
 }
 

+ 13 - 15
packages/web/src/eval.rs

@@ -16,7 +16,7 @@ pub fn init_eval() {
 /// Represents the web-target's provider of evaluators.
 pub struct WebEvalProvider;
 impl EvalProvider for WebEvalProvider {
-    fn new_evaluator(&self, js: String) -> Result<GenerationalBox<Box<dyn Evaluator>>, EvalError> {
+    fn new_evaluator(&self, js: String) -> GenerationalBox<Box<dyn Evaluator>> {
         WebEvaluator::create(js)
     }
 }
@@ -33,12 +33,12 @@ const PROMISE_WRAPPER: &str = r#"
 struct WebEvaluator {
     dioxus: Dioxus,
     channel_receiver: futures_channel::mpsc::UnboundedReceiver<serde_json::Value>,
-    result: Option<serde_json::Value>,
+    result: Option<Result<serde_json::Value, EvalError>>,
 }
 
 impl WebEvaluator {
     /// Creates a new evaluator for web-based targets.
-    fn create(js: String) -> Result<GenerationalBox<Box<dyn Evaluator>>, EvalError> {
+    fn create(js: String) -> GenerationalBox<Box<dyn Evaluator>> {
         let (mut channel_sender, channel_receiver) = futures_channel::mpsc::unbounded();
         let owner = UnsyncStorage::owner();
         let invalid = owner.invalid();
@@ -69,23 +69,21 @@ impl WebEvaluator {
                         let string: String = stringified.into();
                         Value::from_str(&string).map_err(|e| {
                             EvalError::Communication(format!("Failed to parse result - {}", e))
-                        })?
+                        })
                     } else {
-                        return Err(EvalError::Communication(
+                        Err(EvalError::Communication(
                             "Failed to stringify result".into(),
-                        ));
+                        ))
                     }
                 } else {
-                    return Err(EvalError::Communication(
+                    Err(EvalError::Communication(
                         "Failed to stringify result".into(),
-                    ));
+                    ))
                 }
             }
-            Err(err) => {
-                return Err(EvalError::InvalidJs(
-                    err.as_string().unwrap_or("unknown".to_string()),
-                ));
-            }
+            Err(err) => Err(EvalError::InvalidJs(
+                err.as_string().unwrap_or("unknown".to_string()),
+            )),
         };
 
         invalid.set(Box::new(Self {
@@ -94,7 +92,7 @@ impl WebEvaluator {
             result: Some(result),
         }) as Box<dyn Evaluator + 'static>);
 
-        Ok(invalid)
+        invalid
     }
 }
 
@@ -105,7 +103,7 @@ impl Evaluator for WebEvaluator {
         _cx: &mut std::task::Context<'_>,
     ) -> std::task::Poll<Result<serde_json::Value, EvalError>> {
         if let Some(result) = self.result.take() {
-            std::task::Poll::Ready(Ok(result))
+            std::task::Poll::Ready(result)
         } else {
             std::task::Poll::Ready(Err(EvalError::Finished))
         }