mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-10 06:34:20 +00:00
Eval should never return an error
Only awaiting eval should error. Eval should always be available, even if using its methods returns errors.
This commit is contained in:
parent
1145ed7534
commit
cbadea022a
9 changed files with 65 additions and 44 deletions
|
@ -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();
|
||||
|
|
|
@ -45,7 +45,7 @@ fn mock_event(id: &'static str, value: &'static str) {
|
|||
value, id
|
||||
);
|
||||
|
||||
eval(&js).unwrap().await.unwrap();
|
||||
eval(&js).await.unwrap();
|
||||
});
|
||||
})
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@ fn use_inner_html(id: &'static str) -> Option<String> {
|
|||
return element.innerHTML"#,
|
||||
id
|
||||
))
|
||||
.unwrap()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>>();
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
eval_provider
|
||||
.new_evaluator(script.to_string())
|
||||
.map(UseEval::new)
|
||||
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.
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue