Skip to main content

quarb_session/
lib.rs

1//! The backend-agnostic interactive Quarb session.
2//!
3//! The session logic — the `&N` / `&N!` / `&N#` macro history, its
4//! resolution, and rendering coordination — is pure and depends on
5//! two pluggable seams:
6//!
7//! - an [`Executor`]: where the arbor materializes and queries run.
8//!   [`LocalExecutor`] runs in-process (the native full fleet, or the
9//!   wasm text-format subset); a daemon executor (native, elsewhere)
10//!   proxies to a resident process.
11//! - a [`Store`]: where the session's durable state persists — a file
12//!   store on native, a browser store (localStorage) on wasm, or
13//!   [`MemStore`] for none.
14//!
15//! Results cross those seams as [`Cell`]s — node results already
16//! rendered to their locator string, value results keeping their
17//! type — because a raw `NodeId` is meaningless across a socket or
18//! the JS boundary.
19
20pub mod doc;
21mod local;
22mod session;
23mod store;
24
25pub use doc::{Doc, Options};
26pub use local::LocalExecutor;
27pub use session::Session;
28pub use store::{MemStore, SessionState, Store};
29#[cfg(feature = "native")]
30pub use store::FileStore;
31
32use quarb::Value;
33
34/// One result row, rendered so it can cross a process or JS boundary:
35/// a node as its locator string, a value keeping its type.
36#[derive(Clone, Debug)]
37pub enum Cell {
38    Node(String),
39    Value(Value),
40}
41
42impl Cell {
43    /// The line as printed in a terminal.
44    pub fn display(&self) -> String {
45        match self {
46            Cell::Node(s) => s.clone(),
47            Cell::Value(v) => v.to_string(),
48        }
49    }
50}
51
52/// The materialization + query substrate. Implementations run a query
53/// against a standing arbor and return rendered [`Cell`]s.
54///
55/// `query` is the whole text to run — the session prepends its macro
56/// table (`def &N: …;`) so history resolves inline, which also lets it
57/// cross a process boundary (the daemon) as plain text.
58pub trait Executor {
59    fn run(&self, query: &str) -> anyhow::Result<Vec<Cell>>;
60
61    /// Run against a *freshly re-materialized* source — the `&N!`
62    /// live reading. The default re-runs against the standing arbor
63    /// (an immutable source never drifts); executors that can re-open
64    /// the source override it so a live reading sees current data,
65    /// diverging from the frozen `&N#`.
66    fn run_fresh(&self, query: &str) -> anyhow::Result<Vec<Cell>> {
67        self.run(query)
68    }
69}
70
71#[cfg(feature = "native")]
72mod daemon;
73#[cfg(feature = "native")]
74pub use daemon::DaemonExecutor;