webc 5.0.0-rc.6

WebContainer implementation for wapm.io
Documentation
use bytes::{Bytes, BytesMut};

use crate::v2::{
    read::{Section, SectionError},
    Tag,
};

#[derive(Debug, Clone)]
pub(crate) struct Decoder;

impl Decoder {
    pub(crate) fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Section>, DecodeError> {
        let header_size = std::mem::size_of::<u8>() + std::mem::size_of::<u64>();

        if src.len() < header_size {
            return Ok(None);
        }

        let tag = src[0];
        let mut length = [0_u8; 8];
        length.copy_from_slice(&src[1..9]);
        let length: usize = u64::from_le_bytes(length).try_into().unwrap();

        if src.len() < header_size + length {
            // We haven't read the entire section yet
            src.reserve(header_size + length);
            return Ok(None);
        }

        let _header = src.split_to(header_size);
        let data = src.split_to(length).freeze();

        match Section::parse(tag, data.clone()) {
            Ok(s) => Ok(Some(s)),
            Err(error) => Err(DecodeError { error, tag, data }),
        }
    }
}

#[derive(Debug, thiserror::Error)]
#[error("Unable to parse the {} section", Tag::display(*tag))]
pub struct DecodeError {
    #[source]
    pub error: SectionError,
    pub tag: u8,
    pub data: Bytes,
}

#[cfg(test)]
mod tests {
    use crate::{metadata::Manifest, v2::Tag};

    use super::*;

    #[test]
    fn parse_a_single_section() {
        let manifest = Manifest {
            entrypoint: Some("Python".to_string()),
            ..Default::default()
        };
        let serialized_manifest = serde_cbor::to_vec(&manifest).unwrap();
        let section = crate::v2::write::Section::new(
            Tag::Manifest,
            serialized_manifest.clone(),
            crate::v2::ChecksumAlgorithm::None,
        );
        let mut buffer = BytesMut::new();
        section.write_to(&mut buffer);

        let decoded = Decoder.decode(&mut buffer).unwrap().unwrap();

        assert!(buffer.is_empty());
        let reader = match decoded {
            Section::Manifest(r) => r,
            _ => unreachable!(),
        };
        assert_eq!(reader.bytes(), &serialized_manifest);
    }
}