eval.rs 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. use dioxus_core::ScopeId;
  2. use dioxus_document::{Document, Eval, EvalError, Evaluator};
  3. use generational_box::{AnyStorage, GenerationalBox, UnsyncStorage};
  4. use std::rc::Rc;
  5. use crate::query::{Query, QueryEngine};
  6. /// Provides the LiveviewDocument through [`ScopeId::provide_context`].
  7. pub fn init_eval() {
  8. let query = ScopeId::ROOT.consume_context::<QueryEngine>().unwrap();
  9. let provider: Rc<dyn Document> = Rc::new(LiveviewDocument { query });
  10. ScopeId::ROOT.provide_context(provider);
  11. }
  12. /// Reprints the liveview-target's provider of evaluators.
  13. pub struct LiveviewDocument {
  14. query: QueryEngine,
  15. }
  16. impl Document for LiveviewDocument {
  17. fn eval(&self, js: String) -> Eval {
  18. Eval::new(LiveviewEvaluator::create(self.query.clone(), js))
  19. }
  20. }
  21. /// Represents a liveview-target's JavaScript evaluator.
  22. pub(crate) struct LiveviewEvaluator {
  23. query: Query<serde_json::Value>,
  24. }
  25. impl LiveviewEvaluator {
  26. /// Creates a new evaluator for liveview-based targets.
  27. pub fn create(query_engine: QueryEngine, js: String) -> GenerationalBox<Box<dyn Evaluator>> {
  28. let query = query_engine.new_query(&js);
  29. // We create a generational box that is owned by the query slot so that when we drop the query slot, the generational box is also dropped.
  30. let owner = UnsyncStorage::owner();
  31. let query_id = query.id;
  32. let query = owner.insert(Box::new(LiveviewEvaluator { query }) as Box<dyn Evaluator>);
  33. query_engine.active_requests.slab.borrow_mut()[query_id].owner = Some(owner);
  34. query
  35. }
  36. }
  37. impl Evaluator for LiveviewEvaluator {
  38. /// # Panics
  39. /// This will panic if the query is currently being awaited.
  40. fn poll_join(
  41. &mut self,
  42. context: &mut std::task::Context<'_>,
  43. ) -> std::task::Poll<Result<serde_json::Value, EvalError>> {
  44. self.query
  45. .poll_result(context)
  46. .map_err(|e| EvalError::Communication(e.to_string()))
  47. }
  48. /// Sends a message to the evaluated JavaScript.
  49. fn send(&self, data: serde_json::Value) -> Result<(), EvalError> {
  50. if let Err(e) = self.query.send(data) {
  51. return Err(EvalError::Communication(e.to_string()));
  52. }
  53. Ok(())
  54. }
  55. /// Gets an UnboundedReceiver to receive messages from the evaluated JavaScript.
  56. ///
  57. /// # Panics
  58. /// This will panic if the query is currently being awaited.
  59. fn poll_recv(
  60. &mut self,
  61. context: &mut std::task::Context<'_>,
  62. ) -> std::task::Poll<Result<serde_json::Value, EvalError>> {
  63. self.query
  64. .poll_recv(context)
  65. .map_err(|e| EvalError::Communication(e.to_string()))
  66. }
  67. }