Draw a texture handle as the primitive it is

`Painter::primitive` takes `impl PrimitiveLike`: a primitive, or something
that yields one and does whatever else drawing it needs. A `&TextureHandle`
yields a `TexturePrimitive` and retains its share on the way through, so
`texture`, `texture_within` and `texture_at` are gone and an image is drawn
like anything else.

I said last round that the blanket impl would collide with the one for
`&TextureHandle` under coherence. It does not: `Primitive` is ours, so no
crate can add the impl that would overlap, and rustc accepts both.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Opus 5 committed 2026-09-13 16:59:08 -04:00
1 parent 01a9b8633d
commit 23fb71ee56
3 files changed
+31 -20

No files matched your search

+1 -1
View File
@@ -9,7 +9,7 @@ mod render_state;
mod size;
pub use active::*;
pub use painter::Painter;
pub use painter::{Painter, PrimitiveLike};
pub use render_state::*;
pub use size::*;
+29 -18
View File
@@ -52,11 +52,13 @@ impl<'a> Painter<'a> {
}
/// Writes a primitive to be rendered
pub fn primitive<P: Primitive>(&mut self, primitive: P) {
pub fn primitive(&mut self, primitive: impl PrimitiveLike) {
let primitive = primitive.into_primitive(self);
self.primitive_at(primitive, self.region)
}
pub fn primitive_within<P: Primitive>(&mut self, primitive: P, region: UiRegion) {
pub fn primitive_within(&mut self, primitive: impl PrimitiveLike, region: UiRegion) {
let primitive = primitive.into_primitive(self);
self.primitive_at(primitive, region.within(&self.region));
}
@@ -89,22 +91,6 @@ impl<'a> Painter<'a> {
);
}
pub fn texture_within(&mut self, handle: &TextureHandle, region: UiRegion) {
self.texture_at(handle, region.within(&self.region));
}
pub fn texture(&mut self, handle: &TextureHandle) {
self.texture_at(handle, self.region);
}
/// A texture primitive, plus a share of the handle it names -- which a
/// `Pod` primitive cannot carry, and without which the slot could be
/// freed and reused while still drawn.
pub fn texture_at(&mut self, handle: &TextureHandle, region: UiRegion) {
self.textures.push(handle.clone());
self.primitive_at(TexturePrimitive::from(handle), region);
}
pub fn render_text(
&mut self,
buffer: &mut TextBuffer,
@@ -185,3 +171,28 @@ impl<'a> Painter<'a> {
self.state.size_ctx(self.id, self.region.size(), self.rsc)
}
}
/// What `Painter::primitive` takes: a primitive, or something that yields one
/// and does whatever else drawing it needs.
pub trait PrimitiveLike {
type Primitive: Primitive;
fn into_primitive(self, painter: &mut Painter) -> Self::Primitive;
}
impl<P: Primitive> PrimitiveLike for P {
type Primitive = P;
fn into_primitive(self, _: &mut Painter) -> P {
self
}
}
impl PrimitiveLike for &TextureHandle {
type Primitive = TexturePrimitive;
/// Retains a share of the handle, so the slot the primitive names cannot
/// be freed and reused while it is still drawn.
fn into_primitive(self, painter: &mut Painter) -> TexturePrimitive {
painter.textures.push(self.clone());
self.into()
}
}