Skip to main content

Output

Trait Output 

Source
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§

Source

type Error: BackendError

Error type returned by fallible operations.

Required Methods§

Source

fn draw_layers<'a, I>(&mut self, content: I) -> Result<(), Self::Error>
where I: Iterator<Item = DrawCell<'a>>,

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.

Source

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.

Source

fn size(&self) -> Size

Return current display dimensions.

Source

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§

Source

fn draw<'a, I>(&mut self, content: I) -> Result<(), Self::Error>
where I: Iterator<Item = DrawCell<'a>>,

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.

Source

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.

Source

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.

Source

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.

Implementors§