Skip to main content

rosace_core/
element.rs

1use std::sync::Arc;
2
3use crate::component::Component;
4use crate::types::{ComponentId, Key};
5
6/// Type-erased bridge between the element tree and the render layer.
7///
8/// Implemented by `WidgetBox` in `rosace-widgets`. Defined here in
9/// `rosace-core` so `NativeElement` can hold it without a circular dep.
10pub trait WidgetPayload: Send + Sync + 'static {
11    /// Returns `self` as `&dyn Any` so the render walker can downcast.
12    fn as_any(&self) -> &dyn std::any::Any;
13}
14
15/// An element representing a component instance in the tree.
16#[derive(Clone)]
17pub struct ComponentElement {
18    pub id: ComponentId,
19    pub key: Option<Key>,
20    /// The component that produced this element. The walker calls `build()` on it.
21    pub component: Arc<dyn Component>,
22    pub children: Vec<Element>,
23}
24
25/// An element backed by a native widget (a `Box<dyn Widget>`).
26#[derive(Clone)]
27pub struct NativeElement {
28    /// Debug label (type name of the widget).
29    pub tag: &'static str,
30    /// The actual widget, type-erased. Walker downcasts to `WidgetBox`.
31    /// `None` for element-tree-only nodes (e.g. layout-crate containers).
32    pub payload: Option<Arc<dyn WidgetPayload>>,
33    pub children: Vec<Element>,
34    /// Optional stable key for reconciler identity (local to sibling list).
35    pub key: Option<Key>,
36}
37
38/// A plain text leaf node.
39#[derive(Clone)]
40pub struct TextElement {
41    pub content: String,
42}
43
44/// The fundamental unit of the ROSACE element tree.
45///
46/// Elements are lightweight descriptions of what to render. `Component::build()`
47/// returns an `Element`; the framework walks the tree to produce pixels.
48#[derive(Clone)]
49pub enum Element {
50    Component(ComponentElement),
51    Native(NativeElement),
52    Text(TextElement),
53    Empty,
54}
55
56impl Element {
57    pub fn empty() -> Self { Element::Empty }
58
59    pub fn text(content: impl Into<String>) -> Self {
60        Element::Text(TextElement { content: content.into() })
61    }
62
63    /// Attach a stable reconciler key to this element (local to sibling list).
64    pub fn with_key(self, key: impl Into<Key>) -> Self {
65        match self {
66            Element::Native(mut n) => { n.key = Some(key.into()); Element::Native(n) }
67            Element::Component(mut c) => { c.key = Some(key.into()); Element::Component(c) }
68            other => other,
69        }
70    }
71}
72
73impl std::fmt::Debug for Element {
74    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75        match self {
76            Element::Component(c) => write!(f, "Component(id={})", c.id.0),
77            Element::Native(n)    => write!(f, "Native({})", n.tag),
78            Element::Text(t)      => write!(f, "Text({:?})", t.content),
79            Element::Empty        => write!(f, "Empty"),
80        }
81    }
82}