Skip to main content

tilo_app/framework/
delivery.rs

1//! Delivering an admitted invocation to a widget without a host, for a test
2//! that drives a widget directly: handing a control's invocation back, or an
3//! action a published tree encoded. Apps answer their own operations as a
4//! typed effect vocabulary; this reaches only the toolkit's widgets inside
5//! them, the way the host does once it admitted an invocation.
6
7use ui_core::automerge::{AutoCommit, ObjId};
8use ui_core::host_operation::{ResourceOperation, ResourceOperationStart};
9use ui_core::widget::Widget;
10
11use super::Effected;
12
13/// The operation type a toolkit control's invocation travels under.
14const CONTROL_INVOKE: &str = "tilo.ui.control.invoke";
15
16/// Delivering an admitted invocation to a widget, as its host does. Answers
17/// how the widget started it — done at once with its output, or pending to
18/// finish later — or `None` when nothing in the widget answers it.
19pub trait HostDelivery {
20    /// Start the encoded operation (`type_id`, `payload`) of `kind`.
21    ///
22    /// # Errors
23    ///
24    /// Returns the widget's refusal or failure.
25    fn start_encoded(
26        &mut self,
27        kind: tilo_actions::OperationKind,
28        type_id: &str,
29        payload: &[u8],
30        doc: &mut AutoCommit,
31        path: &ObjId,
32    ) -> Result<Option<Effected>, String>;
33
34    /// Hand back the invocation of the toolkit control `control` (its id,
35    /// as its `tilo.control:` resource names it).
36    ///
37    /// # Errors
38    ///
39    /// Returns the widget's refusal or failure.
40    fn deliver_control(
41        &mut self,
42        kind: tilo_actions::OperationKind,
43        control: &str,
44        doc: &mut AutoCommit,
45        path: &ObjId,
46    ) -> Result<Option<Effected>, String> {
47        let payload = serde_json::to_vec(control).map_err(|error| error.to_string())?;
48        self.start_encoded(kind, CONTROL_INVOKE, &payload, doc, path)
49    }
50}
51
52impl<W: Widget + ?Sized> HostDelivery for W {
53    fn start_encoded(
54        &mut self,
55        kind: tilo_actions::OperationKind,
56        type_id: &str,
57        payload: &[u8],
58        doc: &mut AutoCommit,
59        path: &ObjId,
60    ) -> Result<Option<Effected>, String> {
61        let started = self.start_operation(
62            &ResourceOperation::local(tilo_actions::InvocationId::new(), kind, type_id, payload),
63            &mut ui_core::widget::Edits::lend(doc),
64            path,
65        )?;
66        Ok(started.map(|started| match started {
67            ResourceOperationStart::Completed(output) => Effected::Done(output),
68            ResourceOperationStart::Accepted => Effected::Pending,
69        }))
70    }
71}