feat: execute Tessera UI source with embedded Aster
Verify Tessera GUI / verify (push) Successful in 7m38s

This commit is contained in:
2026-10-20 03:35:46 +08:00
parent 3e1cce78f8
commit 8cb2bf8607
14 changed files with 1482 additions and 778 deletions
+49 -4
View File
@@ -1,11 +1,13 @@
use std::collections::HashSet;
use std::sync::Arc;
use anyhow::{Result, bail};
use anyhow::{Context as _, Result, bail};
use serde::{Deserialize, Serialize};
use crate::{
display_list::{Color, DisplayList, DrawCommand},
geometry::{Point, Rect},
ui_bridge::UiNode,
};
pub const DEFAULT_NAMESPACE: &str = "app.main";
@@ -14,6 +16,7 @@ pub const DEFAULT_NAMESPACE: &str = "app.main";
pub struct NamespaceState {
pub name: String,
pub revision: u64,
pub submission: u64,
pub document: RenderDocument,
}
@@ -22,13 +25,49 @@ impl Default for NamespaceState {
Self {
name: DEFAULT_NAMESPACE.to_owned(),
revision: 0,
submission: 0,
document: RenderDocument::default(),
}
}
}
impl NamespaceState {
pub fn next_submission(&self) -> Result<u64> {
self.submission
.checked_add(1)
.context("submission counter exhausted")
}
pub fn commit(&mut self, submission: u64, document: RenderDocument) -> Result<Option<u64>> {
if submission != self.submission {
return Ok(None);
}
let revision = self
.revision
.checked_add(1)
.context("revision counter exhausted")?;
self.document = document;
self.revision = revision;
Ok(Some(revision))
}
pub fn clear(&mut self) -> Result<u64> {
let submission = self.next_submission()?;
let revision = self
.revision
.checked_add(1)
.context("revision counter exhausted")?;
self.submission = submission;
self.document = RenderDocument::default();
self.revision = revision;
Ok(revision)
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct RenderDocument {
#[serde(skip)]
pub ui_root: Option<Arc<UiNode>>,
#[serde(default)]
pub source: String,
#[serde(default)]
@@ -59,9 +98,15 @@ impl RenderDocument {
}
pub fn display_list(&self, scale: f32) -> Result<DisplayList> {
let relayout = self
.ui_root
.as_deref()
.map(crate::layout::frame)
.transpose()?;
let frame = relayout.as_ref().unwrap_or(&self.frame);
let mut list = DisplayList::default();
list.push(DrawCommand::Clear(parse_color(&self.frame.background)?));
for command in &self.frame.commands {
list.push(DrawCommand::Clear(parse_color(&frame.background)?));
for command in &frame.commands {
list.push(command.to_draw_command(scale)?);
}
Ok(list)
@@ -288,7 +333,7 @@ pub fn parse_color(value: &str) -> Result<Color> {
let hex = value
.strip_prefix('#')
.ok_or_else(|| anyhow::anyhow!("color must begin with #"))?;
if hex.len() != 6 && hex.len() != 8 {
if !hex.is_ascii() || (hex.len() != 6 && hex.len() != 8) {
bail!("color must use #RRGGBB or #RRGGBBAA");
}
let parse = |range| u8::from_str_radix(&hex[range], 16);