pub trait Output {
type Error: BackendError;
// Required methods
fn draw_layers<'a, I>(&mut self, content: I) -> Result<(), Self::Error>
where I: Iterator<Item = DrawCell<'a>>;
fn flush(&mut self) -> Result<(), Self::Error>;
fn size(&self) -> Size;
fn clear(&mut self) -> Result<(), Self::Error>;
// Provided methods
fn draw<'a, I>(&mut self, content: I) -> Result<(), Self::Error>
where I: Iterator<Item = DrawCell<'a>> { ... }
fn needs_full_frame(&self) -> bool { ... }
fn composites_layers(&self) -> bool { ... }
fn resize(&mut self, size: Size) { ... }
}Expand description
Draws grid content to a display and reports its dimensions.
This is the only one of the three backend facets (Output, Input, Cursor) that’s
fallible: writing to a real display can fail (a broken pipe, a closed terminal, a lost
surface), so every mutating method here returns Result<(), Self::Error>.
§Examples
use retroglyph_core::backend::{DrawCell, Output};
use retroglyph_core::grid::Size;
struct NullOutput;
impl Output for NullOutput {
type Error = core::convert::Infallible;
fn draw_layers<'a, I>(&mut self, _content: I) -> Result<(), Self::Error>
where
I: Iterator<Item = DrawCell<'a>>,
{
Ok(())
}
fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
fn size(&self) -> Size {
Size::new(4, 2)
}
fn clear(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}Required Associated Types§
Sourcetype Error: BackendError
type Error: BackendError
Error type returned by fallible operations.
Required Methods§
Sourcefn draw_layers<'a, I>(&mut self, content: I) -> Result<(), Self::Error>
fn draw_layers<'a, I>(&mut self, content: I) -> Result<(), Self::Error>
Draw changed cells across all layers.
crate::terminal::Terminal::present always calls this method, never draw
directly, for every backend. A backend that renders one glyph per cell and returns
false from composites_layers (the default) receives a
stream present has already pre-flattened onto layer 0 (all allocated layers
composited into one frame first, so layers 1+ still appear on every backend, not only
pixel ones); implementing this is no different from what implementing single-layer
draw used to mean. A pixel/GPU backend that returns true from composites_layers
receives the real, multi-layer stream here and does its own compositing (per-pixel or
per-quad, plus sub-cell offsets and transparency as needed).
When needs_full_frame returns true, this
receives all cells from every allocated layer, and the backend
should clear its output surface before drawing.
That promise holds only together with composites_layers() == true:
crate::terminal::Terminal::present only reads needs_full_frame inside its composites_layers
branch, so a backend
returning true here with the default (false) composites_layers never actually
receives a full frame, despite this doc’s unconditional wording (retroglyph#763). No
backend in this workspace uses that combination; a future one that does should either
also return true from composites_layers, or treat needs_full_frame as dead until
Terminal::present’s dispatch is widened to honor it outside that branch too.
Items are the same DrawCell draw receives, read through
DrawCell::layer rather than a separate element.
§Errors
Self::Error is implementation-defined (a broken pipe or closed terminal for a
process-backed display, a lost surface for a windowed one); implementations do not
roll back cells already written before the failure. Because
crate::terminal::Terminal::present only swaps its diff buffers into previous after the
call that reached this method succeeds, a failed draw leaves the same cells marked
dirty, so they are resent on the next successful present rather than silently
dropped.
Sourcefn flush(&mut self) -> Result<(), Self::Error>
fn flush(&mut self) -> Result<(), Self::Error>
Flush buffered output to the display.
§Errors
Self::Error is implementation-defined (a broken pipe, a closed terminal, a lost
surface). crate::terminal::Terminal::present calls this only after
draw/draw_layers succeed, and swaps its diff
buffers only after flush also succeeds; a failed flush therefore leaves the
current frame’s cells buffered but unconfirmed, and they are resent on the next
successful present.
Sourcefn clear(&mut self) -> Result<(), Self::Error>
fn clear(&mut self) -> Result<(), Self::Error>
Clear the entire display.
§Errors
Self::Error is implementation-defined (a broken pipe, a closed terminal, a lost
surface). Unlike draw/flush, this is not part of
crate::terminal::Terminal::present’s per-frame path; callers that invoke it directly
(some backends also call it internally on resize) should treat a failure as leaving
the display in an unknown, possibly partially cleared state and retry or tear down
rather than assume the previous contents are still intact.
Provided Methods§
Sourcefn draw<'a, I>(&mut self, content: I) -> Result<(), Self::Error>
fn draw<'a, I>(&mut self, content: I) -> Result<(), Self::Error>
Draw changed cells to the output surface, layer 0 only.
Every cell arrives as a DrawCell, which carries the out-of-line state a Tile
cannot: its full grapheme cluster and its tint. Both live in a side table on
Grid
rather than in the tile, so a backend that needs either must read it from here.
The default implementation forwards to draw_layers, which every
backend implements. crate::terminal::Terminal::present never calls this method directly (it
always goes through draw_layers, pre-flattened onto layer 0 for a backend that doesn’t
composite; see composites_layers), so overriding this is
only worthwhile if a backend has a cheaper direct path for the known-single-layer case
than its own draw_layers would take.
§Errors
See draw_layers, which this forwards to by default and shares
its error contract with.
Sourcefn needs_full_frame(&self) -> bool
fn needs_full_frame(&self) -> bool
Returns true if the backend needs the entire frame (all cells on
all layers) on every call to draw_layers, rather
than just the changed cells.
Pixel-based backends (e.g. SoftwareRenderer) need this because
sub-cell offsets can spill glyph pixels into adjacent cells: without
a full redraw, orphaned pixels from the previous frame linger.
Only takes effect alongside composites_layers returning
true: see draw_layers’s docs for why a true here paired with
the default composites_layers does nothing.
The default implementation returns false.
Sourcefn composites_layers(&self) -> bool
fn composites_layers(&self) -> bool
Whether this backend composites layers itself (per pixel or quad),
receiving the raw layered stream from draw_layers.
Backends that render one glyph per cell return false (the default) and
receive a pre-flattened, single-layer stream: crate::terminal::Terminal::present
composites all allocated layers into one frame first. This makes layers
1+ appear on every backend, not only pixel backends. Pixel/GPU backends
return true and composite the layers themselves.
Sourcefn resize(&mut self, size: Size)
fn resize(&mut self, size: Size)
Notify the backend of a resize to size, updating what size reports.
Called automatically by crate::terminal::Terminal::resize after both grids are resized.
Backends that maintain internal state tied to terminal dimensions (such as
Headless) should override this to update that state. The default
implementation is a no-op.
A driver may also call this directly, ahead of and independent from
crate::terminal::Terminal::resize, to keep size in sync with an underlying
surface the moment it changes (a windowed backend reacting to an OS resize, for
example) without waiting for the app to resize the terminal’s grid content in
response. Doing so does not resize the grid; only crate::terminal::Terminal::resize does that.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.