use crate::{Error, KineticEdgeKey, Result};
pub(super) fn decode_edges(
reader: &mut Reader<'_>,
vertex_count: usize,
maximum: usize,
) -> Result<Vec<KineticEdgeKey>> {
let count = reader.bounded_usize("edge count", maximum)?;
if count > reader.remaining() / 16 {
return Err(Error::InvalidInput(
"coverage edge count exceeds the remaining bytes".into(),
));
}
let edges = (0..count)
.map(|_| {
Ok(KineticEdgeKey {
u: reader.usize()?,
v: reader.usize()?,
})
})
.collect::<Result<Vec<_>>>()?;
if edges
.iter()
.any(|edge| edge.u >= edge.v || edge.v >= vertex_count)
|| edges.windows(2).any(|pair| pair[0] >= pair[1])
{
return Err(Error::InvalidInput(
"coverage edges are not canonical".into(),
));
}
Ok(edges)
}
pub(super) fn decode_usizes(reader: &mut Reader<'_>, maximum: usize) -> Result<Vec<usize>> {
let count = reader.bounded_usize("integer list count", maximum)?;
if count > reader.remaining() / 8 {
return Err(Error::InvalidInput(
"coverage integer list exceeds the remaining bytes".into(),
));
}
(0..count).map(|_| reader.usize()).collect()
}
pub(super) fn decode_indices(
reader: &mut Reader<'_>,
exclusive_maximum: usize,
maximum_count: usize,
) -> Result<Vec<usize>> {
let values = decode_usizes(reader, maximum_count)?;
if values.iter().any(|value| *value >= exclusive_maximum)
|| values.windows(2).any(|pair| pair[0] >= pair[1])
{
return Err(Error::InvalidInput(
"coverage index list is not canonical".into(),
));
}
Ok(values)
}
pub(in crate::coverage_synthesis::wire) struct Reader<'a> {
bytes: &'a [u8],
position: usize,
}
impl<'a> Reader<'a> {
pub(in crate::coverage_synthesis::wire) fn new(bytes: &'a [u8]) -> Self {
Self { bytes, position: 0 }
}
pub(super) fn remaining(&self) -> usize {
self.bytes.len() - self.position
}
pub(super) fn take(&mut self, count: usize) -> Result<&'a [u8]> {
let end = self
.position
.checked_add(count)
.ok_or_else(|| Error::InvalidInput("coverage artifact position overflows".into()))?;
if end > self.bytes.len() {
return Err(Error::InvalidInput("coverage artifact is truncated".into()));
}
let value = &self.bytes[self.position..end];
self.position = end;
Ok(value)
}
pub(super) fn bounded_usize(&mut self, name: &str, maximum: usize) -> Result<usize> {
let value = self.usize()?;
if value > maximum {
return Err(Error::InvalidInput(format!(
"coverage {name} exceeds its limit"
)));
}
Ok(value)
}
pub(super) fn u8(&mut self) -> Result<u8> {
Ok(self.take(1)?[0])
}
pub(super) fn u16(&mut self) -> Result<u16> {
Ok(u16::from_be_bytes(self.take(2)?.try_into().unwrap()))
}
pub(super) fn u32(&mut self) -> Result<u32> {
Ok(u32::from_be_bytes(self.take(4)?.try_into().unwrap()))
}
pub(super) fn u64(&mut self) -> Result<u64> {
Ok(u64::from_be_bytes(self.take(8)?.try_into().unwrap()))
}
pub(super) fn usize(&mut self) -> Result<usize> {
usize::try_from(self.u64()?)
.map_err(|_| Error::InvalidInput("coverage integer does not fit usize".into()))
}
pub(super) fn optional_u64(&mut self) -> Result<Option<u64>> {
match self.u8()? {
0 => Ok(None),
1 => Ok(Some(self.u64()?)),
_ => Err(Error::InvalidInput(
"coverage optional integer flag is invalid".into(),
)),
}
}
pub(super) fn optional_usize(&mut self) -> Result<Option<usize>> {
match self.u8()? {
0 => Ok(None),
1 => Ok(Some(self.usize()?)),
_ => Err(Error::InvalidInput(
"coverage optional integer flag is invalid".into(),
)),
}
}
pub(super) fn array32(&mut self) -> Result<[u8; 32]> {
Ok(self.take(32)?.try_into().unwrap())
}
}