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 compositing(&self) -> Compositing { ... }
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 returns Compositing::CellFlattened
(the default, from compositing) 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 Compositing::PixelLayered 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 compositing returns PixelLayered { needs_full_frame: true },
this receives all cells from every allocated layer, and the backend should clear its
output surface before drawing; PixelLayered { needs_full_frame: false } and
CellFlattened both receive only the changed cells.
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 compositing), 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 compositing(&self) -> Compositing
fn compositing(&self) -> Compositing
How this backend wants layers handed to draw_layers.
Backends that render one glyph per cell return Compositing::CellFlattened
(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 Compositing::PixelLayered and composite the
layers themselves; its needs_full_frame field asks for all cells on every
draw_layers call (all cells on all layers) rather than just the
changed ones, because pixel-based backends (e.g. SoftwareRenderer) can spill glyph
pixels from sub-cell offsets into adjacent cells: without a full redraw, orphaned pixels
from the previous frame linger.
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".