#[inline]
pub fn encode_arg_sequence<T: AsRef<[u8]>>(args: &[T], out: &mut [u8]) -> usize {
let count = args.len() as u32;
out[..4].copy_from_slice(&count.to_le_bytes());
let mut cursor = 4;
for arg in args {
let slice = arg.as_ref();
out[cursor..cursor + 4].copy_from_slice(&(slice.len() as u32).to_le_bytes());
cursor += 4;
out[cursor..cursor + slice.len()].copy_from_slice(slice);
cursor += slice.len();
}
cursor
}
#[inline]
pub fn arg_sequence_len(args: &[impl AsRef<[u8]>]) -> usize {
4 + args.iter().map(|a| 4 + a.as_ref().len()).sum::<usize>()
}
pub fn decode_arg_slices(mut bytes: &[u8]) -> Option<Vec<&[u8]>> {
let count = u32::from_le_bytes(*bytes.first_chunk::<4>()?) as usize;
bytes = &bytes[4..];
let mut args = Vec::with_capacity(count.min(bytes.len() / 4));
for _ in 0..count {
let len = u32::from_le_bytes(*bytes.first_chunk::<4>()?) as usize;
bytes = bytes.get(4..)?;
args.push(bytes.get(..len)?);
bytes = &bytes[len..];
}
Some(args)
}
#[inline]
pub fn decode_arg_sequence(bytes: &[u8]) -> Option<Vec<Vec<u8>>> {
decode_arg_slices(bytes).map(|slices| slices.into_iter().map(<[u8]>::to_vec).collect())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn arg_sequence_roundtrip() {
let args = vec![b"k".to_vec(), b"v".to_vec(), vec![]];
let mut buf = vec![0u8; arg_sequence_len(&args)];
let written = encode_arg_sequence(&args, &mut buf);
assert_eq!(written, buf.len());
assert_eq!(decode_arg_sequence(&buf).unwrap(), args);
let slices = decode_arg_slices(&buf).unwrap();
assert_eq!(slices, vec![&b"k"[..], &b"v"[..], &b""[..]]);
assert!(decode_arg_slices(&buf[..buf.len() - 1]).is_none());
assert!(decode_arg_slices(&[]).is_none());
assert!(decode_arg_sequence(&buf[..buf.len() - 1]).is_none());
assert!(decode_arg_sequence(&[]).is_none());
}
}