Skip to main content

quillmark_core/
session.rs

1use std::any::Any;
2
3use crate::{Diagnostic, RenderError, RenderOptions, RenderResult};
4
5/// Backend-specific session implementation.
6///
7/// Implementors must be `'static` (required by `Any`), `Send`, and `Sync`. The
8/// `'static` bound prevents borrowing source data — own anything you need to
9/// keep alive for the session's lifetime.
10#[doc(hidden)]
11pub trait SessionHandle: Any + Send + Sync {
12    fn render(&self, opts: &RenderOptions) -> Result<RenderResult, RenderError>;
13    fn page_count(&self) -> usize;
14    fn as_any(&self) -> &dyn Any;
15}
16
17/// Opaque, backend-backed iterative render session.
18pub struct RenderSession {
19    inner: Box<dyn SessionHandle>,
20    warnings: Vec<Diagnostic>,
21}
22
23impl RenderSession {
24    #[doc(hidden)]
25    pub fn new(inner: Box<dyn SessionHandle>) -> Self {
26        Self {
27            inner,
28            warnings: Vec::new(),
29        }
30    }
31
32    /// Borrow the underlying [`SessionHandle`] for typed-side-channel access.
33    ///
34    /// Bindings call this and downcast via [`SessionHandle::as_any`] to reach
35    /// backend-specific surfaces (e.g. `quillmark_typst::typst_session_of`
36    /// for canvas preview). Intentionally `#[doc(hidden)]` — the shape of
37    /// this accessor is not part of the stable public API.
38    #[doc(hidden)]
39    pub fn handle(&self) -> &dyn SessionHandle {
40        &*self.inner
41    }
42
43    /// Attach session-level warnings. Appended to [`RenderResult::warnings`]
44    /// on every [`RenderSession::render`] call and surfaced verbatim by
45    /// [`RenderSession::warnings`].
46    pub fn with_warnings(mut self, warnings: Vec<Diagnostic>) -> Self {
47        self.warnings = warnings;
48        self
49    }
50
51    pub fn page_count(&self) -> usize {
52        self.inner.page_count()
53    }
54
55    /// Snapshot of session-level warnings attached at `Backend::open` time.
56    ///
57    /// Empty when the backend produced none. These are also appended to
58    /// [`RenderResult::warnings`] on each [`RenderSession::render`] call;
59    /// this accessor surfaces them to consumers (e.g. canvas previews) that
60    /// don't go through `render()`.
61    pub fn warnings(&self) -> &[Diagnostic] {
62        &self.warnings
63    }
64
65    pub fn render(&self, opts: &RenderOptions) -> Result<RenderResult, RenderError> {
66        let mut result = self.inner.render(opts)?;
67        result.warnings.extend(self.warnings.iter().cloned());
68        Ok(result)
69    }
70}