Skip to main content

quarb_session/
local.rs

1//! The in-process executor: materialize and query a [`Doc`] here.
2//!
3//! Serves both native (the full adapter fleet) and wasm (the
4//! text-format subset) — the two differ only in which `Doc` variants
5//! compile. A native executor may also carry its source spec, so a
6//! `&N!` live reading can re-open the source and see current data.
7
8use crate::doc::Doc;
9use crate::{Cell, Executor};
10use quarb::QueryResult;
11
12pub struct LocalExecutor {
13    doc: Doc,
14    /// The invocation instant `now()` denotes, bound once per session.
15    now: (i64, u32),
16    allow_shell: bool,
17    /// The source spec, kept so a `&N!` reading can re-materialize.
18    /// `None` when the source can't be re-opened (wasm pasted text,
19    /// which never drifts anyway).
20    #[cfg(feature = "native")]
21    respec: Option<(Vec<std::path::PathBuf>, crate::Options)>,
22}
23
24impl LocalExecutor {
25    /// An executor over a fixed materialized `Doc` (no live re-read).
26    pub fn new(doc: Doc, now: (i64, u32), allow_shell: bool) -> Self {
27        Self {
28            doc,
29            now,
30            allow_shell,
31            #[cfg(feature = "native")]
32            respec: None,
33        }
34    }
35
36    /// A native executor that can re-materialize its source for a
37    /// `&N!` live reading.
38    #[cfg(feature = "native")]
39    pub fn with_respec(
40        doc: Doc,
41        now: (i64, u32),
42        allow_shell: bool,
43        paths: Vec<std::path::PathBuf>,
44        opts: crate::Options,
45    ) -> Self {
46        Self {
47            doc,
48            now,
49            allow_shell,
50            respec: Some((paths, opts)),
51        }
52    }
53}
54
55/// Run one query against a `Doc`, rendering its result to [`Cell`]s.
56fn run_doc(doc: &Doc, query: &str, now: (i64, u32), allow_shell: bool) -> anyhow::Result<Vec<Cell>> {
57    let result = doc
58        .run(query, now, allow_shell)
59        .map_err(|e| anyhow::anyhow!("{e}"))?;
60    Ok(match result {
61        QueryResult::Nodes(nodes) => nodes.into_iter().map(|n| Cell::Node(doc.render(n))).collect(),
62        QueryResult::Values(values) => values.into_iter().map(Cell::Value).collect(),
63    })
64}
65
66impl Executor for LocalExecutor {
67    fn run(&self, query: &str) -> anyhow::Result<Vec<Cell>> {
68        run_doc(&self.doc, query, self.now, self.allow_shell)
69    }
70
71    fn run_fresh(&self, query: &str) -> anyhow::Result<Vec<Cell>> {
72        #[cfg(feature = "native")]
73        if let Some((paths, opts)) = &self.respec {
74            let fresh = match paths.as_slice() {
75                [one] => Doc::open(one, opts)?,
76                many => Doc::mount(many, opts)?,
77            };
78            return run_doc(&fresh, query, self.now, self.allow_shell);
79        }
80        self.run(query)
81    }
82}