use crate::bytes::{le_u32, le_u64};
use crate::error::UrnaError;
use crate::layout::SECTION_BLOB_SPAN_OVERLAY;
pub const BLOB_SPAN_OVERLAY_PAYLOAD_VERSION: u32 = 1;
pub const BLOB_REF_NONE: u32 = 0xFFFF_FFFF;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct BlobSpanEntry {
pub blob_ref_index: u32,
pub byte_start: u64,
pub byte_end: u64,
}
fn malformed(reason: impl Into<String>) -> UrnaError {
UrnaError::MalformedSectionPayload {
section_id: SECTION_BLOB_SPAN_OVERLAY,
reason: reason.into(),
}
}
pub fn encode_blob_span_overlay(entries: &[BlobSpanEntry]) -> Result<Vec<u8>, UrnaError> {
let mut out = Vec::with_capacity(12 + entries.len() * 16);
out.extend_from_slice(&BLOB_SPAN_OVERLAY_PAYLOAD_VERSION.to_le_bytes());
out.extend_from_slice(&(entries.len() as u64).to_le_bytes());
for e in entries {
out.extend_from_slice(&e.blob_ref_index.to_le_bytes());
out.extend_from_slice(&e.byte_start.to_le_bytes());
out.extend_from_slice(&e.byte_end.to_le_bytes());
}
Ok(out)
}
pub fn decode_blob_span_overlay(bytes: &[u8]) -> Result<Vec<BlobSpanEntry>, UrnaError> {
let mut cur = Cursor::new(bytes);
let version = cur.u32()?;
if version != BLOB_SPAN_OVERLAY_PAYLOAD_VERSION {
return Err(UrnaError::UnsupportedSectionVersion {
section_id: SECTION_BLOB_SPAN_OVERLAY,
version,
});
}
let n = cur.u64()? as usize;
if n > (bytes.len() - cur.pos) / 16 {
return Err(malformed("blob_span_overlay: entry count exceeds payload"));
}
let mut entries = Vec::with_capacity(n);
for _ in 0..n {
entries.push(BlobSpanEntry {
blob_ref_index: cur.u32()?,
byte_start: cur.u64()?,
byte_end: cur.u64()?,
});
}
if cur.pos != bytes.len() {
return Err(malformed("trailing bytes after entries"));
}
Ok(entries)
}
struct Cursor<'a> {
buf: &'a [u8],
pos: usize,
}
impl<'a> Cursor<'a> {
fn new(buf: &'a [u8]) -> Self {
Self { buf, pos: 0 }
}
fn take(&mut self, n: usize) -> Result<&'a [u8], UrnaError> {
if n > self.buf.len() - self.pos {
return Err(malformed("unexpected EOF"));
}
let s = &self.buf[self.pos..self.pos + n];
self.pos += n;
Ok(s)
}
fn u32(&mut self) -> Result<u32, UrnaError> {
le_u32(self.take(4)?)
}
fn u64(&mut self) -> Result<u64, UrnaError> {
le_u64(self.take(8)?)
}
}