Struct ElementTree

Source
pub struct ElementTree<A> { /* private fields */ }
Expand description

Retained element tree produced by reconciliation.

Element and widget IDs are monotonically allocated within one tree and start at one. Storage uses a hash map, so iteration order is unspecified. Relationship fields are not automatically repaired when callers use the low-level mutation/removal APIs.

§Examples

use ailloli_ui_runtime::element::{ElementKind, ElementTree};
let mut tree = ElementTree::<()>::new();
let root = tree.create_element(ElementKind::Empty, None, None);
assert_eq!(tree.root(), Some(root));
assert!(tree.get(root).unwrap().dirty.layout);

Implementations§

Source§

impl<A> ElementTree<A>

Provides the operations defined for ElementTree<A>.

Source

pub fn new() -> Self

Creates an empty tree with zeroed ID counters and diagnostics.

§Examples
use ailloli_ui_runtime::element::ElementTree;
let tree = ElementTree::<()>::new();
assert!(tree.root().is_none());
assert_eq!(tree.iter_elements().count(), 0);
Source

pub fn root(&self) -> Option<ElementId>

Returns the first element ever created as the retained root.

None means no element has yet been created. Low-level Self::remove_element does not clear this field, so removing the root can leave a stale Some(id); reconciliation owns normal root lifetime.

§Examples
use ailloli_ui_runtime::element::{ElementKind, ElementTree};
let mut tree = ElementTree::<()>::new();
let id = tree.create_element(ElementKind::Empty, None, None);
assert_eq!(tree.root(), Some(id));
Source

pub fn get(&self, id: ElementId) -> Option<&Element<A>>

Borrows an element by ID, returning None for unknown or removed IDs.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::element::ElementTree;
let tree = ElementTree::<()> ::new();
assert!(tree.get(ElementId(1)).is_none());
Source

pub fn get_mut(&mut self, id: ElementId) -> Option<&mut Element<A>>

Mutably borrows an element by ID.

Direct edits can bypass revision, cache, parent/child, and diagnostic invariants. None is returned for unknown or removed IDs.

§Examples
use ailloli_ui_runtime::element::{ElementKind, ElementTree, Key};
let mut tree = ElementTree::<()>::new();
let id = tree.create_element(ElementKind::Empty, None, None);
tree.get_mut(id).unwrap().key = Some(Key::Static("root"));
assert_eq!(tree.get(id).unwrap().key, Some(Key::Static("root")));
Source

pub fn create_element( &mut self, kind: ElementKind<A>, key: Option<Key>, parent: Option<ElementId>, ) -> ElementId

Allocates and inserts one dirty retained element.

Element and widget counters are incremented independently and the new IDs start at one. The first inserted element becomes root; later insertions do not change it. The element starts layout+paint dirty with layout/topology revisions 1, no cached layout/bounds, default view metadata, and caller-supplied parent stored verbatim. It is not automatically added to the parent’s child list.

§Panics

Panics before changing either counter if either u64 identifier space is exhausted. Identifiers are never wrapped or silently reused.

§Examples
use ailloli_ui_runtime::element::{ElementKind, ElementTree, Key};
let mut tree = ElementTree::<()>::new();
let id = tree.create_element(ElementKind::Empty, Some(Key::U64(9)), None);
let element = tree.get(id).unwrap();
assert_eq!(id.0, 1);
assert_eq!(element.key, Some(Key::U64(9)));
Source

pub fn set_children(&mut self, parent: ElementId, children: Vec<ElementId>)

Replaces a parent’s ordered direct-child IDs when the vector differs.

A real change increments topology and layout revisions with wrapping but reserves zero as a sentinel, clears the layout cache key, marks layout and paint dirty, and requests commit. Equal vectors and unknown parent IDs are no-ops. This method does not update each child’s parent, reject duplicates, or verify that IDs exist.

§Examples
use ailloli_ui_runtime::element::{ElementKind, ElementTree};
let mut tree = ElementTree::<()>::new();
let parent = tree.create_element(ElementKind::Empty, None, None);
let child = tree.create_element(ElementKind::Empty, None, Some(parent));
tree.set_children(parent, vec![child]);
assert_eq!(tree.children_of(parent), &[child]);
Source

pub fn children_of(&self, parent: ElementId) -> &[ElementId]

Borrows direct-child IDs in retained order.

Unknown parent IDs return a shared empty slice, making missing and childless parents indistinguishable through this accessor.

§Examples
use ailloli_ui_core::ElementId;
use ailloli_ui_runtime::element::ElementTree;
let tree = ElementTree::<()>::new();
assert_eq!(tree.children_of(ElementId(99)), &[]);
Source

pub fn parent_of(&self, id: ElementId) -> Option<ElementId>

Returns an element’s stored parent ID.

None represents an unknown element, a root, or a detached element. This accessor does not verify that the returned parent still exists.

§Examples
use ailloli_ui_runtime::element::{ElementKind, ElementTree};
let mut tree = ElementTree::<()>::new();
let parent = tree.create_element(ElementKind::Empty, None, None);
let child = tree.create_element(ElementKind::Empty, None, Some(parent));
assert_eq!(tree.parent_of(child), Some(parent));
Source

pub fn is_ancestor_of(&self, ancestor: ElementId, descendant: ElementId) -> bool

Returns true if ancestor is an ancestor of descendant (inclusive).

Equal IDs return true even if no such element exists. Otherwise the method follows stored parent pointers until None; malformed parent cycles that do not contain ancestor cause an infinite loop.

§Examples
use ailloli_ui_runtime::element::{ElementKind, ElementTree};
let mut tree = ElementTree::<()>::new();
let root = tree.create_element(ElementKind::Empty, None, None);
let child = tree.create_element(ElementKind::Empty, None, Some(root));
assert!(tree.is_ancestor_of(root, child));
assert!(!tree.is_ancestor_of(child, root));
Source

pub fn set_layout(&mut self, id: ElementId, layout: LayoutResult)

Stores a layout and clears only layout and paint dirty flags.

Unknown IDs are ignored. This low-level setter leaves input dirtiness, cache identity, layout-change/commit flags, and committed bounds untouched; normal layout should use crate::layout::LayoutEngine.

§Examples
use ailloli_ui_runtime::element::{ElementKind, ElementTree};
use ailloli_ui_runtime::layout::LayoutResult;
let mut tree = ElementTree::<()>::new();
let id = tree.create_element(ElementKind::Empty, None, None);
tree.set_layout(id, LayoutResult::empty());
assert!(tree.get(id).unwrap().layout.is_some());
assert!(!tree.get(id).unwrap().dirty.layout);
Source

pub fn set_view_metadata( &mut self, id: ElementId, flex_item: FlexItemStyle, size_hint: LayoutSizeHint, )

Replaces flex-item and declarative size metadata without invalidation.

Unknown IDs are ignored. Reconciliation separately invalidates the element before using this helper.

§Examples
use ailloli_ui_core::style::{FlexItemStyle, LayoutSizeHint};
use ailloli_ui_runtime::element::{ElementKind, ElementTree};
let mut tree = ElementTree::<()>::new();
let id = tree.create_element(ElementKind::Empty, None, None);
let flex = FlexItemStyle { flex_grow: 2.0, ..Default::default() };
tree.set_view_metadata(id, flex, LayoutSizeHint::default());
assert_eq!(tree.get(id).unwrap().flex_item.flex_grow, 2.0);
Source

pub fn set_layout_debug(&mut self, id: ElementId, debug: LayoutDebugInfo)

Stores developer-tooling layout data for an existing element.

Unknown IDs are ignored and no dirty/revision state changes.

§Examples
use ailloli_ui_core::{Constraints, Size};
use ailloli_ui_runtime::layout::LayoutDebugInfo;
let debug = LayoutDebugInfo {
    constraints_in: Constraints::tight(1.0, 2.0),
    constraints_final: None,
    layout_size: Size::new(1.0, 2.0),
};
assert_eq!(debug.layout_size.h, 2.0);
Source

pub fn remove_element(&mut self, id: ElementId) -> Option<Element<A>>

Removes and returns exactly one element.

A removal diagnostic is recorded even when the ID is absent. This low-level operation does not recurse, unlink parent/children, clear the root field, or remove runtime state. Reconciliation uses a private subtree-aware path for normal deletion.

§Examples
use ailloli_ui_runtime::element::{ElementKind, ElementTree};
let mut tree = ElementTree::<()>::new();
let id = tree.create_element(ElementKind::Empty, None, None);
assert_eq!(tree.remove_element(id).unwrap().id, id);
assert!(tree.get(id).is_none());
assert_eq!(tree.root(), Some(id)); // low-level root reference is unchanged
Source

pub fn iter_elements(&self) -> impl Iterator<Item = (ElementId, &Element<A>)>

Iterates all stored elements as (id, reference) pairs.

Hash-map order is unspecified and may differ across runs. The iterator borrows the tree and allocates nothing.

§Examples
use ailloli_ui_runtime::element::{ElementKind, ElementTree};
let mut tree = ElementTree::<()>::new();
tree.create_element(ElementKind::Empty, None, None);
tree.create_element(ElementKind::Empty, None, None);
assert_eq!(tree.iter_elements().count(), 2);
Source

pub fn diagnostics(&self) -> ElementTreeDiagnosticsSnapshot

Returns a point-in-time copy of saturating per-element work counters.

Reading diagnostics does not clear them.

§Examples
use ailloli_ui_runtime::element::ElementTree;
let tree = ElementTree::<()>::new();
assert!(tree.diagnostics().elements.is_empty());
Source

pub fn resolve_element_by_view_key( &self, key: &str, ) -> Result<ElementId, ViewKeyResolveError>

Resolves a unique view key in the window (at most one element per key).

Owned Key::String and borrowed Key::Static values compare by text; Key::U64 values are ignored. Missing and duplicate matches return typed errors. Scanning is O(number_of_elements) and allocates a vector of matching IDs; hash-map iteration does not affect a unique result.

§Errors

Returns ViewKeyResolveError::Missing for zero matches and ViewKeyResolveError::Duplicate with the exact count for two or more.

§Examples
use ailloli_ui_runtime::element::{ElementKind, ElementTree, Key, ViewKeyResolveError};
let mut tree = ElementTree::<()>::new();
let id = tree.create_element(ElementKind::Empty, Some(Key::Static("search")), None);
assert_eq!(tree.resolve_element_by_view_key("search"), Ok(id));
assert!(matches!(tree.resolve_element_by_view_key("missing"),
    Err(ViewKeyResolveError::Missing { .. })));

Trait Implementations§

Source§

impl<A> Default for ElementTree<A>

Implements the Default contract for ElementTree<A>.

Source§

fn default() -> Self

Constructs the documented default value.

Auto Trait Implementations§

§

impl<A> !Freeze for ElementTree<A>

§

impl<A> !RefUnwindSafe for ElementTree<A>

§

impl<A> !Send for ElementTree<A>

§

impl<A> !Sync for ElementTree<A>

§

impl<A> Unpin for ElementTree<A>

§

impl<A> !UnwindSafe for ElementTree<A>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> ErasedDestructor for T
where T: 'static,