perf(wire): pre-size effect batch encoding
This commit is contained in:
+76
-1
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user