Skip to content

Feature: Relax draw() closure 'static bound #53

@subinium

Description

@subinium

Problem

draw() requires FnOnce + 'static (container.rs:1183):

pub fn draw(self, f: impl FnOnce(&mut Buffer, Rect) + 'static)

This forces users to .clone() all captured state every frame, since local borrows can't satisfy 'static. For data-dense UIs (e.g., a 12×16 step grid), this means cloning the entire pattern state into the closure 60 times per second.

Root Cause

The closure is stored in ctx.deferred_draws as Box<dyn FnOnce(&mut Buffer, Rect)>, executed after the UI closure returns during run_frame_kernel (lib.rs:1073-1089). Since it runs after the UI closure's stack frame is gone, it can't borrow from it.

However, the closures are consumed within the same run_frame_kernel call (line 1078: c.take() followed by cb(buffer, rdr.rect)). They never escape the function.

Proposed Solution

A frame-scoped lifetime bound instead of 'static:

pub fn draw<'frame>(self, f: impl FnOnce(&mut Buffer, Rect) + 'frame)

This would require architectural changes to the command/layout pipeline to support bounded lifetimes on stored closures, but would dramatically improve ergonomics for custom drawing.

Alternative: draw_ref()

A simpler short-term fix: add a draw_ref() that executes the closure immediately during the command-building phase (before layout), writing to a temporary buffer that gets composited during layout. This avoids the deferred execution entirely:

pub fn draw_ref(self, f: impl FnOnce(&mut Buffer, Rect))  // no 'static needed

Source Reference

  • container.rs:1183draw() signature with 'static
  • core.rs:44deferred_draws: Vec<Option<RawDrawCallback>>
  • lib.rs:1073-1089 — deferred draw execution

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions