holos-tda 0.9.0

Vietoris-Rips persistence and checked degree-Rips modules
Documentation
use super::model::ProgramArtifactError;

pub(super) fn put_u16(out: &mut Vec<u8>, value: u16) {
    out.extend_from_slice(&value.to_be_bytes());
}

pub(super) fn put_u32(out: &mut Vec<u8>, value: u32) {
    out.extend_from_slice(&value.to_be_bytes());
}

pub(super) fn put_u64(out: &mut Vec<u8>, value: u64) {
    out.extend_from_slice(&value.to_be_bytes());
}

pub(super) fn put_usize(
    out: &mut Vec<u8>,
    value: usize,
    label: &str,
) -> std::result::Result<(), ProgramArtifactError> {
    let value = u64::try_from(value)
        .map_err(|_| ProgramArtifactError::new(format!("{label} does not fit the wire format")))?;
    put_u64(out, value);
    Ok(())
}

pub(super) fn put_optional_f64(out: &mut Vec<u8>, value: Option<f64>) {
    match value {
        None => out.push(0),
        Some(value) => {
            out.push(1);
            put_u64(out, value.to_bits());
        }
    }
}

pub(super) struct Reader<'a> {
    bytes: &'a [u8],
    position: usize,
}

impl<'a> Reader<'a> {
    pub(super) 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,
    ) -> std::result::Result<&'a [u8], ProgramArtifactError> {
        let end = self
            .position
            .checked_add(count)
            .ok_or_else(|| ProgramArtifactError::new("byte position overflows usize"))?;
        if end > self.bytes.len() {
            return Err(ProgramArtifactError::new("truncated envelope"));
        }
        let value = &self.bytes[self.position..end];
        self.position = end;
        Ok(value)
    }

    pub(super) fn u8(&mut self) -> std::result::Result<u8, ProgramArtifactError> {
        Ok(self.take(1)?[0])
    }

    pub(super) fn u16(&mut self) -> std::result::Result<u16, ProgramArtifactError> {
        Ok(u16::from_be_bytes(
            self.take(2)?.try_into().expect("two-byte slice"),
        ))
    }

    pub(super) fn u32(&mut self) -> std::result::Result<u32, ProgramArtifactError> {
        Ok(u32::from_be_bytes(
            self.take(4)?.try_into().expect("four-byte slice"),
        ))
    }

    pub(super) fn u64(&mut self) -> std::result::Result<u64, ProgramArtifactError> {
        Ok(u64::from_be_bytes(
            self.take(8)?.try_into().expect("eight-byte slice"),
        ))
    }

    pub(super) fn usize(&mut self) -> std::result::Result<usize, ProgramArtifactError> {
        usize::try_from(self.u64()?)
            .map_err(|_| ProgramArtifactError::new("wire integer does not fit usize"))
    }

    pub(super) fn bounded_usize(
        &mut self,
        label: &str,
        limit: usize,
    ) -> std::result::Result<usize, ProgramArtifactError> {
        let value = self.usize()?;
        if value > limit {
            return Err(ProgramArtifactError::new(format!(
                "{label} {value} exceeds the limit {limit}"
            )));
        }
        Ok(value)
    }

    pub(super) fn optional_f64(
        &mut self,
    ) -> std::result::Result<Option<f64>, ProgramArtifactError> {
        match self.u8()? {
            0 => Ok(None),
            1 => Ok(Some(f64::from_bits(self.u64()?))),
            tag => Err(ProgramArtifactError::new(format!(
                "unknown optional-float tag {tag}"
            ))),
        }
    }

    pub(super) fn array32(&mut self) -> std::result::Result<[u8; 32], ProgramArtifactError> {
        Ok(self.take(32)?.try_into().expect("32-byte slice"))
    }
}