feat: new styles

This commit is contained in:
faynot
2026-07-08 23:45:37 +03:00
parent 9c279015dc
commit 75af23930f
18 changed files with 3556 additions and 816 deletions

View File

@@ -7,81 +7,115 @@ pub struct Reader<'a> {
}
impl<'a> Reader<'a> {
#[inline(always)]
pub fn new(data: &'a [u8]) -> Self {
Self { data, pos: 0 }
}
#[inline(always)]
pub fn remaining(&self) -> usize {
self.data.len() - self.pos
}
#[inline(always)]
fn require(&self, n: usize) -> Result<(), InterpError> {
if self.pos + n > self.data.len() {
Err(InterpError::UnexpectedEof)
} else {
Ok(())
}
}
#[inline(always)]
pub fn read_byte(&mut self) -> Result<u8, InterpError> {
self.require(1)?;
let b = self.data[self.pos];
let b = unsafe { *self.data.get_unchecked(self.pos) };
self.pos += 1;
Ok(b)
}
#[inline(always)]
pub fn read_u32(&mut self) -> Result<u32, InterpError> {
self.require(4)?;
let v = u32::from_le_bytes(self.data[self.pos..self.pos + 4].try_into().unwrap());
let v = unsafe {
let ptr = self.data.as_ptr().add(self.pos) as *const [u8; 4];
u32::from_le_bytes(std::ptr::read_unaligned(ptr))
};
self.pos += 4;
Ok(v)
}
#[inline(always)]
pub fn read_i64(&mut self) -> Result<i64, InterpError> {
self.require(8)?;
let v = i64::from_le_bytes(self.data[self.pos..self.pos + 8].try_into().unwrap());
let v = unsafe {
let ptr = self.data.as_ptr().add(self.pos) as *const [u8; 8];
i64::from_le_bytes(std::ptr::read_unaligned(ptr))
};
self.pos += 8;
Ok(v)
}
#[inline(always)]
pub fn read_f64(&mut self) -> Result<f64, InterpError> {
self.require(8)?;
let v = f64::from_le_bytes(self.data[self.pos..self.pos + 8].try_into().unwrap());
let v = unsafe {
let ptr = self.data.as_ptr().add(self.pos) as *const [u8; 8];
f64::from_le_bytes(std::ptr::read_unaligned(ptr))
};
self.pos += 8;
Ok(v)
}
#[inline(always)]
pub fn read_str_ref(&mut self) -> Result<&'a str, InterpError> {
let len = self.read_u32()? as usize;
self.require(len)?;
let slice = &self.data[self.pos .. self.pos + len];
self.pos += len;
unsafe {
Ok(std::str::from_utf8_unchecked(slice))
}
}
#[inline(always)]
pub fn read_string(&mut self) -> Result<String, InterpError> {
self.read_str_ref().map(|s| s.to_owned())
}
#[inline(always)]
pub fn skip_string(&mut self) -> Result<(), InterpError> {
let len = self.read_u32()? as usize;
self.require(len)?;
let s = std::str::from_utf8(&self.data[self.pos..self.pos + len])
.map_err(|_| InterpError::InvalidUtf8)?
.to_string();
self.pos += len;
Ok(s)
Ok(())
}
pub fn read_value_as_string(&mut self, type_op: u8) -> Result<Option<String>, InterpError> {
let s = match type_op {
OP_PROP_STR | OP_PROP_COLOR | OP_PROP_FSPATH | OP_PROP_RHEI => {
Some(self.read_string()?)
}
OP_PROP_IDENT => {
OP_PROP_STR | OP_PROP_COLOR | OP_PROP_FSPATH | OP_PROP_RHEI | OP_PROP_IDENT => {
Some(self.read_string()?)
}
OP_PROP_VAR => {
Some(format!("${}", self.read_string()?))
}
OP_PROP_INT => {
Some(self.read_i64()?.to_string())
}
OP_PROP_FLOAT => {
Some(self.read_f64()?.to_string())
}
OP_PROP_BOOL => {
Some((self.read_byte()? != 0).to_string())
let name = self.read_str_ref()?;
let mut s = String::with_capacity(name.len() + 1);
s.push('$');
s.push_str(name);
Some(s)
}
OP_PROP_INT => Some(self.read_i64()?.to_string()),
OP_PROP_FLOAT => Some(self.read_f64()?.to_string()),
OP_PROP_BOOL => Some((self.read_byte()? != 0).to_string()),
OP_PROP_NULL => None,
OP_PROP_ARRAY => {
let items = self.read_array_as_strings()?;
Some(items.join(","))
}
OP_PROP_UNIT => {
let num = self.read_f64()?;
let unit = self.read_string()?;
let num = self.read_f64()?;
let unit = self.read_str_ref()?;
if num.fract() == 0.0 {
Some(format!("{}{}", num as i64, unit))
} else {
@@ -89,13 +123,12 @@ impl<'a> Reader<'a> {
}
}
OP_PROP_CALL => {
let name = self.read_string()?;
let name = self.read_string()?;
let arg_count = self.read_u32()? as usize;
let mut args = Vec::with_capacity(arg_count);
let mut args = Vec::with_capacity(arg_count);
for _ in 0..arg_count {
let op = self.read_byte()?;
let val = self.read_value_as_string(op)?
.unwrap_or_default();
let op = self.read_byte()?;
let val = self.read_value_as_string(op)?.unwrap_or_default();
args.push(val);
}
Some(format!("{}({})", name, args.join(",")))
@@ -105,7 +138,6 @@ impl<'a> Reader<'a> {
Ok(s)
}
/// Read `OP_PROP_ARRAY` (opcode already consumed) and return elements as strings.
pub fn read_array_as_strings(&mut self) -> Result<Vec<String>, InterpError> {
let count = self.read_u32()? as usize;
let mut items = Vec::with_capacity(count);
@@ -118,21 +150,15 @@ impl<'a> Reader<'a> {
Ok(items)
}
pub fn skip_value(&mut self, type_op: u8) -> Result<(), InterpError> {
match type_op {
OP_PROP_STR
| OP_PROP_COLOR
| OP_PROP_FSPATH
| OP_PROP_VAR
| OP_PROP_RHEI
| OP_PROP_IDENT => {
self.read_string()?;
OP_PROP_STR | OP_PROP_COLOR | OP_PROP_FSPATH | OP_PROP_VAR | OP_PROP_RHEI | OP_PROP_IDENT => {
self.skip_string()?;
}
OP_PROP_INT => { self.read_i64()?; }
OP_PROP_INT => { self.read_i64()?; }
OP_PROP_FLOAT => { self.read_f64()?; }
OP_PROP_BOOL => { self.read_byte()?; }
OP_PROP_NULL => {}
OP_PROP_BOOL => { self.read_byte()?; }
OP_PROP_NULL => {}
OP_PROP_ARRAY => {
let count = self.read_u32()?;
for _ in 0..count {
@@ -141,11 +167,11 @@ impl<'a> Reader<'a> {
}
}
OP_PROP_UNIT => {
self.read_f64()?; // number
self.read_string()?; // unit suffix
self.read_f64()?;
self.skip_string()?;
}
OP_PROP_CALL => {
self.read_string()?; // function name
self.skip_string()?;
let arg_count = self.read_u32()?;
for _ in 0..arg_count {
let op = self.read_byte()?;
@@ -157,49 +183,38 @@ impl<'a> Reader<'a> {
Ok(())
}
/// Skip a full opcode + its payload without interpreting it.
pub fn skip_opcode(&mut self, op: u8) -> Result<(), InterpError> {
match op {
OP_VERSION => { self.read_i64()?; }
OP_STYLE | OP_RHEI_BLK => { self.read_string()?; }
OP_VERSION => { self.read_i64()?; }
OP_STYLE | OP_RHEI_BLK => { self.skip_string()?; }
OP_PROP_STR
| OP_PROP_COLOR
| OP_PROP_FSPATH
| OP_PROP_VAR
| OP_PROP_RHEI
| OP_PROP_INT
| OP_PROP_FLOAT
| OP_PROP_BOOL
| OP_PROP_NULL
| OP_PROP_ARRAY
| OP_PROP_CALL
| OP_PROP_UNIT
| OP_PROP_IDENT => {
self.read_string()?; // key
self.skip_value(op)?; // value
OP_PROP_STR | OP_PROP_COLOR | OP_PROP_FSPATH | OP_PROP_VAR | OP_PROP_RHEI |
OP_PROP_INT | OP_PROP_FLOAT | OP_PROP_BOOL | OP_PROP_NULL | OP_PROP_ARRAY |
OP_PROP_CALL | OP_PROP_UNIT | OP_PROP_IDENT => {
self.skip_string()?;
self.skip_value(op)?;
}
OP_GLOBAL | OP_LET => {
self.read_string()?;
self.skip_string()?;
let vop = self.read_byte()?;
self.skip_value(vop)?;
}
OP_SINGLETON => {
self.read_string()?;
self.skip_string()?;
let count = self.read_u32()?;
for _ in 0..count {
self.read_string()?;
self.skip_string()?;
let vop = self.read_byte()?;
self.skip_value(vop)?;
}
}
OP_COMPONENT => {
self.read_string()?;
self.skip_string()?;
let params = self.read_u32()?;
for _ in 0..params {
self.read_string()?;
self.read_string()?;
self.skip_string()?;
self.skip_string()?;
}
self.skip_block()?;
}
@@ -210,50 +225,48 @@ impl<'a> Reader<'a> {
if self.read_byte()? == 1 { self.skip_block()?; }
}
OP_EACH => {
self.read_string()?;
self.skip_string()?;
let vop = self.read_byte()?;
self.skip_value(vop)?;
self.skip_block()?;
}
OP_ON => {
self.read_string()?;
self.skip_string()?;
let args = self.read_u32()?;
for _ in 0..args {
self.read_string()?;
self.skip_string()?;
let vop = self.read_byte()?;
self.skip_value(vop)?;
}
self.skip_block()?;
}
OP_ELEM_PUSH => { self.read_string()?; }
OP_CONTENT => {
OP_ELEM_PUSH => { self.skip_string()?; }
OP_CONTENT => {
let vop = self.read_byte()?;
self.skip_value(vop)?;
}
OP_STYLE_RULE => {
self.read_string()?; // selector
self.skip_string()?;
let count = self.read_u32()?;
for _ in 0..count {
self.read_string()?; // property key
self.skip_string()?;
let vop = self.read_byte()?;
self.skip_value(vop)?; // property value
self.skip_value(vop)?;
}
}
OP_STYLE_ANIM => {
self.read_string()?; // animation name
self.skip_string()?;
let frame_count = self.read_u32()?;
for _ in 0..frame_count {
self.read_string()?; // step ("from", "to", "50%", …)
self.skip_string()?;
let prop_count = self.read_u32()?;
for _ in 0..prop_count {
self.read_string()?;
self.skip_string()?;
let vop = self.read_byte()?;
self.skip_value(vop)?;
}
}
}
_ => {}
}
Ok(())
@@ -266,15 +279,4 @@ impl<'a> Reader<'a> {
self.skip_opcode(op)?;
}
}
#[inline]
fn require(&self, n: usize) -> Result<(), InterpError> {
if self.remaining() < n {
Err(InterpError::UnexpectedEof)
} else {
Ok(())
}
}
}