use alloc::vec::Vec;
use super::DecodeError;
pub(crate) const VERSION: u8 = 0x02;
pub(crate) const SLUG_LEN: usize = 32;
pub(crate) const MIN_LEN: usize = 1 + SLUG_LEN;
pub(crate) fn assemble(payload: Vec<u8>, slug: &[u8; SLUG_LEN]) -> Vec<u8> {
let mut artifact = Vec::with_capacity(1 + payload.len() + SLUG_LEN);
artifact.push(VERSION);
artifact.extend_from_slice(&payload);
artifact.extend_from_slice(slug);
artifact
}
pub(crate) fn disassemble(encoded: &[u8]) -> Result<(Vec<u8>, [u8; SLUG_LEN]), DecodeError> {
if encoded.len() < MIN_LEN {
return Err(DecodeError::InputTooShort);
}
if encoded[0] != VERSION {
return Err(DecodeError::InvalidVersion(encoded[0]));
}
let split = encoded.len() - SLUG_LEN;
let payload = encoded[1..split].to_vec();
let mut slug = [0u8; SLUG_LEN];
slug.copy_from_slice(&encoded[split..]);
Ok((payload, slug))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn too_short_is_reported_before_version() {
let mut buf = [0u8; 32];
buf[0] = VERSION;
assert_eq!(disassemble(&buf), Err(DecodeError::InputTooShort));
}
#[test]
fn wrong_version_is_rejected() {
let mut buf = [0u8; MIN_LEN];
buf[0] = 0x01;
assert_eq!(disassemble(&buf), Err(DecodeError::InvalidVersion(0x01)));
}
#[test]
fn splits_payload_and_tail_slug() {
let slug = [0xa5u8; SLUG_LEN];
let payload = alloc::vec![0xde, 0xad, 0xbe, 0xef];
let artifact = {
let mut a = alloc::vec![VERSION];
a.extend_from_slice(&payload);
a.extend_from_slice(&slug);
a
};
let (got_payload, got_slug) = disassemble(&artifact).unwrap();
assert_eq!(got_payload, payload);
assert_eq!(got_slug, slug);
}
#[test]
fn minimum_length_artifact_has_empty_payload() {
let slug = [0x11u8; SLUG_LEN];
let mut artifact = alloc::vec![VERSION];
artifact.extend_from_slice(&slug);
let (payload, got_slug) = disassemble(&artifact).unwrap();
assert!(payload.is_empty());
assert_eq!(got_slug, slug);
}
}