use vyre_driver::error::{Error, Result};
pub(crate) const MAGIC: [u8; 8] = *b"VYREPART";
pub(crate) const MAX_PART_COUNT: usize = 1_048_576;
pub const MAX_SERIALIZED_PART_BYTES: usize = 256 * 1024 * 1024;
#[inline]
pub fn encode_parts(parts: &[&[u8]]) -> Result<Vec<u8>> {
if parts.len() > MAX_PART_COUNT {
return Err(Error::Serialization {
message: format!(
"serialized frame has {} parts, exceeding {MAX_PART_COUNT}. Fix: split the frame into fewer parts before encoding.",
parts.len()
),
});
}
for part in parts {
if part.len() > MAX_SERIALIZED_PART_BYTES {
return Err(Error::Serialization {
message: format!(
"serialized part is {} bytes, exceeding {MAX_SERIALIZED_PART_BYTES}. Fix: split the payload into smaller parts before framing.",
part.len()
),
});
}
}
let payload_len = parts.iter().try_fold(0usize, |sum, part| {
sum.checked_add(8)
.and_then(|value| value.checked_add(part.len()))
.ok_or_else(|| Error::Serialization {
message: "SerializationOverflow: framed part size calculation overflow. Fix: split the payload into smaller encode_parts calls.".to_string(),
})
})?;
let total = MAGIC.len().checked_add(payload_len).ok_or_else(|| Error::Serialization {
message: "SerializationOverflow: framed output size calculation overflow. Fix: split the payload into smaller encode_parts calls.".to_string(),
})?;
let mut out = Vec::new();
reserve_encoded_frame(&mut out, total)?;
out.extend_from_slice(&MAGIC);
for part in parts {
let len = u64::try_from(part.len()).map_err(|source| Error::Serialization {
message: format!("framed part length {} exceeds u64::MAX: {source}. Fix: split the payload before framing.", part.len()),
})?;
out.extend_from_slice(&len.to_le_bytes());
out.extend_from_slice(part);
}
Ok(out)
}
fn reserve_encoded_frame(out: &mut Vec<u8>, total: usize) -> Result<()> {
out.try_reserve_exact(total).map_err(|source| Error::Serialization {
message: format!(
"could not reserve {total} encoded frame bytes exactly: {source}. Fix: split the payload into smaller encode_parts calls."
),
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn encode_parts_uses_fallible_exact_reservation() {
let production = include_str!("encode_parts.rs")
.split("\n#[cfg(test)]\nmod tests")
.next()
.expect("Fix: serializer encoder production section should precede tests");
assert!(
!production.contains("Vec::with_capacity"),
"Fix: encode_parts must not use infallible frame allocation."
);
assert!(
production.contains("try_reserve_exact(total)"),
"Fix: encode_parts should reserve the validated frame length fallibly before appending."
);
}
#[test]
fn encode_parts_capacity_matches_validated_frame_size() {
let parts = [b"abc".as_slice(), b"defgh".as_slice()];
let encoded = encode_parts(&parts).expect("Fix: small frame should encode");
let expected = MAGIC.len() + 8 + 3 + 8 + 5;
assert_eq!(encoded.len(), expected);
assert_eq!(
encoded.capacity(),
expected,
"Fix: encode_parts should reserve exactly the validated frame length."
);
}
}