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. Intentionally `#[doc(hidden)]` — the shape
36 /// of this accessor is not part of the stable public API.
37 #[doc(hidden)]
38 pub fn handle(&self) -> &dyn SessionHandle {
39 &*self.inner
40 }
41
42 /// Attach session-level warnings, surfaced by [`RenderSession::warnings`]
43 /// and appended to [`RenderResult::warnings`] on every
44 /// [`RenderSession::render`] call.
45 ///
46 /// A [`Backend`](crate::Backend) chains this onto the session it returns
47 /// from `open` to carry non-fatal open-time diagnostics. The built-in Typst
48 /// backend emits none, so the channel stays empty unless a backend opts in.
49 pub fn with_warnings(mut self, warnings: Vec<Diagnostic>) -> Self {
50 self.warnings = warnings;
51 self
52 }
53
54 pub fn page_count(&self) -> usize {
55 self.inner.page_count()
56 }
57
58 /// Session-level warnings attached at `Backend::open` time, also appended
59 /// to [`RenderResult::warnings`] on each [`RenderSession::render`] call.
60 /// Exposed for consumers (e.g. canvas previews) that never call `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}