Skip to main content

tabnas_alchemy/shared/
route.rs

1//! Captures as data: what a router is asked to recognize and what it
2//! delivers.
3//!
4//! A router (transduce's `Router`, which alchemy reaches through
5//! [`Routers::router`](crate::shared::Routers::router)) feeds every event
6//! through one matcher for all of its [`CaptureSpec`]s and hands each
7//! completed match to a [`RouteSink`]. A `Materialize` capture is built into
8//! a [`Datum`] under a byte budget and delivered when its value completes;
9//! an `Observe` capture delivers only the path, at the value's end, and
10//! retains nothing. These are the types on either side of it; the router
11//! itself is transduce's.
12
13use std::sync::Arc;
14
15use crate::shared::datum::Datum;
16use crate::shared::error::Fail;
17use crate::shared::matcher::CaptureId;
18use crate::shared::selector::{Path, Selector};
19use crate::shared::sink::Flow;
20
21/// What a capture keeps of its match.
22#[derive(Clone, Copy, Debug, PartialEq, Eq)]
23pub enum CaptureMode {
24    /// Build the value and deliver it whole.
25    Materialize,
26    /// Deliver only that the value occurred, and where, when it ends.
27    Observe,
28}
29
30/// The byte budget one materialized capture may not exceed, named after
31/// the `Limits` field the failure reports.
32#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33pub struct Budget {
34    pub bytes: usize,
35    pub name: &'static str,
36}
37
38/// One capture: a tag for the consumer, the selector to match, the mode.
39#[derive(Clone, Debug, PartialEq, Eq)]
40pub struct CaptureSpec {
41    /// Shared with every `Selected` delivered for this capture, so a
42    /// delivery costs a reference count and no allocation.
43    pub tag: Arc<str>,
44    pub selector: Selector,
45    pub mode: CaptureMode,
46    /// The budget for a `Materialize` capture; `None` takes the router's
47    /// `max_capture_bytes`. A stage with a more specific limit (a table's
48    /// rows under `max_record_bytes`) sets it so the failure names that.
49    pub budget: Option<Budget>,
50}
51
52impl CaptureSpec {
53    pub fn new(tag: impl Into<Arc<str>>, selector: Selector, mode: CaptureMode) -> CaptureSpec {
54        CaptureSpec {
55            tag: tag.into(),
56            selector,
57            mode,
58            budget: None,
59        }
60    }
61
62    pub fn materialize(tag: impl Into<Arc<str>>, selector: Selector) -> CaptureSpec {
63        CaptureSpec::new(tag, selector, CaptureMode::Materialize)
64    }
65
66    pub fn observe(tag: impl Into<Arc<str>>, selector: Selector) -> CaptureSpec {
67        CaptureSpec::new(tag, selector, CaptureMode::Observe)
68    }
69
70    pub fn budget(mut self, bytes: usize, name: &'static str) -> CaptureSpec {
71        self.budget = Some(Budget { bytes, name });
72        self
73    }
74}
75
76/// One completed match.
77#[derive(Clone, Debug, PartialEq)]
78pub struct Selected {
79    /// The spec's position in the router's list, for dispatch without a
80    /// string comparison.
81    pub id: CaptureId,
82    pub tag: Arc<str>,
83    pub path: Path,
84    /// The value for a `Materialize` capture; `None` for `Observe`.
85    pub value: Option<Datum>,
86}
87
88/// The consumer of a router's matches.
89pub trait RouteSink {
90    /// A capture's value is beginning at `path`'s position. Nothing has
91    /// been retained for it yet, so a consumer that knows the value is
92    /// out of order can refuse it here at no cost; the router adds the
93    /// path to a failure that has none.
94    fn began(&mut self, id: CaptureId, tag: &str) -> Result<(), Fail> {
95        let _ = (id, tag);
96        Ok(())
97    }
98
99    fn selected(&mut self, selected: Selected) -> Result<Flow, Fail>;
100
101    /// The document ended, validated. Exactly once, after the last match.
102    fn end(&mut self) -> Result<Flow, Fail>;
103}
104
105impl RouteSink for Vec<Selected> {
106    fn selected(&mut self, selected: Selected) -> Result<Flow, Fail> {
107        self.push(selected);
108        Ok(Flow::Continue)
109    }
110
111    fn end(&mut self) -> Result<Flow, Fail> {
112        Ok(Flow::Continue)
113    }
114}
115
116/// A route sink made of a closure; `end` is a no-op.
117pub struct FnRoute<F>(pub F);
118
119impl<F> RouteSink for FnRoute<F>
120where
121    F: FnMut(Selected) -> Result<Flow, Fail>,
122{
123    fn selected(&mut self, selected: Selected) -> Result<Flow, Fail> {
124        (self.0)(selected)
125    }
126
127    fn end(&mut self) -> Result<Flow, Fail> {
128        Ok(Flow::Continue)
129    }
130}