perf(wire): pre-size effect batch encoding

This commit is contained in:
slhx agent
2026-07-13 09:32:46 +02:00
parent ecbdea5cd0
commit 945122cb02
4 changed files with 189 additions and 2 deletions
+76 -1
View File
@@ -459,9 +459,18 @@ pub struct EffectBatch {
}
impl EffectBatch {
/// Return the exact number of bytes produced by [`Self::to_wire`].
pub fn encoded_len(&self) -> usize {
batch_wire_len(self)
}
pub fn to_wire(&self) -> Vec<u8> {
let mut out = Vec::new();
let encoded_len = self.encoded_len();
let mut out = Vec::with_capacity(encoded_len);
let initial_capacity = out.capacity();
write_batch(self, &mut out);
debug_assert_eq!(out.len(), encoded_len);
debug_assert_eq!(out.capacity(), initial_capacity);
out
}
@@ -492,6 +501,72 @@ pub enum WireError {
}
const WIRE_MAGIC: &[u8; 4] = b"HEMX";
const WIRE_BATCH_HEADER_LEN: usize = WIRE_MAGIC.len() + 4 + 8 + 4;
fn batch_wire_len(batch: &EffectBatch) -> usize {
WIRE_BATCH_HEADER_LEN + batch.ops.iter().map(effect_wire_len).sum::<usize>()
}
fn effect_wire_len(effect: &Effect) -> usize {
1 + match effect {
Effect::Put { target, payload } => ref_wire_len(target) + payload_wire_len(payload),
Effect::Insert {
target,
key,
payload,
}
| Effect::Prepend {
target,
key,
payload,
} => ref_wire_len(target) + str_wire_len(key) + payload_wire_len(payload),
Effect::Remove { target, key } => {
ref_wire_len(target) + option_str_wire_len(key.as_deref())
}
Effect::Move {
target,
key,
before,
} => ref_wire_len(target) + str_wire_len(key) + option_str_wire_len(before.as_deref()),
Effect::Focus { target } => ref_wire_len(target),
Effect::Navigate {
url, scroll, title, ..
} => {
str_wire_len(url) + 1 + scroll_wire_len(scroll) + option_str_wire_len(title.as_deref())
}
Effect::Emit { name, payload } => str_wire_len(name) + str_wire_len(payload),
}
}
fn ref_wire_len(reference: &ResourceRef) -> usize {
1 + 4
+ 1
+ match &reference.scope {
None => 0,
Some(ScopeKey::KeyValue(value) | ScopeKey::Field(value)) => str_wire_len(value),
}
}
fn payload_wire_len(payload: &Payload) -> usize {
1 + match payload {
Payload::Text(value) | Payload::Html(value) => str_wire_len(value),
}
}
fn scroll_wire_len(scroll: &ScrollBehavior) -> usize {
1 + match scroll {
ScrollBehavior::Preserve | ScrollBehavior::Top => 0,
ScrollBehavior::Element(target) => ref_wire_len(target),
}
}
fn option_str_wire_len(value: Option<&str>) -> usize {
1 + value.map_or(0, str_wire_len)
}
const fn str_wire_len(value: &str) -> usize {
4 + value.len()
}
fn write_batch(batch: &EffectBatch, out: &mut Vec<u8>) {
out.extend_from_slice(WIRE_MAGIC);