runmat-execution-artifact 0.6.2

Canonical execution bundles and program artifacts for RunMat
Documentation
use std::io::Read;

use crate::{ArtifactError, ArtifactResult, ExecutionBundle, LogicalObject, ObjectDescriptor};

use super::{
    canonical::read_bytes,
    manifest_codec::{decode_descriptor, decode_manifest},
    ArchiveLimits, MAGIC,
};

pub fn read_bundle(
    mut reader: impl Read,
    limits: ArchiveLimits,
) -> ArtifactResult<ExecutionBundle> {
    let mut magic = vec![0_u8; MAGIC.len()];
    reader.read_exact(&mut magic)?;
    if magic != MAGIC {
        return Err(ArtifactError::Invalid(
            "invalid bundle archive magic".into(),
        ));
    }
    let mut total = 0_u64;
    let manifest = read_bytes(&mut reader, limits.max_manifest_bytes, &mut total)?;
    let manifest = decode_manifest(&manifest)?;
    let mut encoded_count = [0_u8; 4];
    reader.read_exact(&mut encoded_count)?;
    let count = u32::from_be_bytes(encoded_count);
    if count > limits.max_objects {
        return Err(ArtifactError::Limit("too many archive objects".into()));
    }
    let mut objects = Vec::with_capacity(count as usize);
    for _ in 0..count {
        let descriptor = read_bytes(&mut reader, limits.max_manifest_bytes, &mut total)?;
        let descriptor: ObjectDescriptor = decode_descriptor(&descriptor)?;
        let bytes = read_bytes(&mut reader, limits.max_object_bytes, &mut total)?;
        if total > limits.max_total_bytes {
            return Err(ArtifactError::Limit("archive is too large".into()));
        }
        objects.push(LogicalObject { descriptor, bytes });
    }
    let mut trailing = [0_u8; 1];
    if reader.read(&mut trailing)? != 0 {
        return Err(ArtifactError::Invalid(
            "bundle archive contains trailing bytes".into(),
        ));
    }
    let bundle = ExecutionBundle { manifest, objects };
    bundle.validate()?;
    Ok(bundle)
}