use crate::{Error, StackBuffer};
use core::convert::TryFrom;
use core::mem::size_of;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Length {
Indefinite,
Definite(usize),
}
impl TryFrom<&[u8]> for Length {
type Error = Error;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
try_from(bytes).map(|(length, _rest)| length)
}
}
impl Length {
const LONG_FLAG: u8 = 0x80;
const MAX_SHORT: u8 = Self::LONG_FLAG - 1;
const INDEFINITE: u8 = 0x80;
}
impl Length {
#[inline]
pub fn to_bytes(&self) -> impl AsRef<[u8]> {
let mut buffer = StackBuffer::new();
match *self {
Length::Indefinite => unsafe { buffer.push(Length::INDEFINITE) },
Length::Definite(mut val) => {
if val <= Length::MAX_SHORT as usize {
unsafe { buffer.push(val as u8) };
} else {
let len = (8 * size_of::<usize>() - (val.leading_zeros() as usize) + 7) / 8 + 1;
unsafe { buffer.set_len(len) };
buffer[0] = Length::LONG_FLAG + (len - 1) as u8;
for i in (1..len).rev() {
debug_assert!(0 < val);
buffer[i] = val as u8;
val >>= 8;
}
debug_assert_eq!(0, val);
}
}
}
buffer
}
}
#[inline]
pub fn try_from(bytes: &[u8]) -> Result<(Length, &[u8]), Error> {
let first = *bytes.get(0).ok_or(Error::UnTerminatedBytes)?;
let bytes = &bytes[1..];
if first == Length::INDEFINITE {
Ok((Length::Indefinite, bytes))
} else if first & Length::LONG_FLAG != Length::LONG_FLAG {
Ok((Length::Definite(first as usize), bytes))
} else {
let second = *bytes.get(0).ok_or(Error::UnTerminatedBytes)?;
if second == 0x00 {
return Err(Error::RedundantBytes);
}
let followings_count = (first & !Length::LONG_FLAG) as usize;
if bytes.len() < followings_count {
return Err(Error::UnTerminatedBytes);
}
if size_of::<usize>() < followings_count {
return Err(Error::OverFlow);
}
let len = bytes[..followings_count]
.iter()
.fold(0, |acc, o| (acc << 8) + (*o as usize));
let bytes = &bytes[followings_count..];
Ok((Length::Definite(len), bytes))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn try_from_just() {
let empty: &[u8] = &[];
{
let bytes: &[u8] = &[0x80];
let res = try_from(bytes).unwrap();
assert_eq!((Length::Indefinite, empty), res);
}
{
let bytes: &[u8] = &[0x00];
let res = try_from(bytes).unwrap();
assert_eq!((Length::Definite(0), empty), res);
let bytes: &[u8] = &[0x7f];
let res = try_from(bytes).unwrap();
assert_eq!((Length::Definite(0x7f), empty), res);
}
{
let bytes: &[u8] = &[0x81, 0x80];
let res = try_from(bytes).unwrap();
assert_eq!((Length::Definite(0x80), empty), res);
let bytes: &[u8] = &[0x81, 0xff];
let res = try_from(bytes).unwrap();
assert_eq!((Length::Definite(0xff), empty), res);
}
{
let bytes: &[u8] = &[0x82, 0x01, 0x00];
let res = try_from(bytes).unwrap();
assert_eq!((Length::Definite(0x0100), empty), res);
let bytes: &[u8] = &[0x82, 0xff, 0xff];
let res = try_from(bytes).unwrap();
assert_eq!((Length::Definite(0xffff), empty), res);
}
{
let mut bytes: [u8; size_of::<usize>() + 1] = [0xff; size_of::<usize>() + 1];
bytes[0] = 0x80 + (size_of::<usize>() as u8);
let res = try_from(&bytes).unwrap();
assert_eq!((Length::Definite(usize::MAX), empty), res);
}
}
#[test]
fn try_from_extra() {
let extra: &[u8] = &[1, 2, 3];
{
let mut bytes = vec![0x80];
bytes.extend(extra);
let res = try_from(bytes.as_ref()).unwrap();
assert_eq!((Length::Indefinite, extra), res);
}
{
let mut bytes = vec![0x00];
bytes.extend(extra);
let res = try_from(bytes.as_ref()).unwrap();
assert_eq!((Length::Definite(0), extra), res);
let mut bytes = vec![0x7f];
bytes.extend(extra);
let res = try_from(bytes.as_ref()).unwrap();
assert_eq!((Length::Definite(0x7f), extra), res);
}
{
let mut bytes = vec![0x81, 0x80];
bytes.extend(extra);
let res = try_from(bytes.as_ref()).unwrap();
assert_eq!((Length::Definite(0x80), extra), res);
let mut bytes = vec![0x81, 0xff];
bytes.extend(extra);
let res = try_from(bytes.as_ref()).unwrap();
assert_eq!((Length::Definite(0xff), extra), res);
}
{
let mut bytes = vec![0x82, 0x01, 0x00];
bytes.extend(extra);
let res = try_from(bytes.as_ref()).unwrap();
assert_eq!((Length::Definite(0x0100), extra), res);
let mut bytes = vec![0x82, 0xff, 0xff];
bytes.extend(extra);
let res = try_from(bytes.as_ref()).unwrap();
assert_eq!((Length::Definite(0xffff), extra), res);
}
{
let mut bytes: [u8; size_of::<usize>() + 1] = [0xff; size_of::<usize>() + 1];
bytes[0] = 0x80 + (size_of::<usize>() as u8);
let mut bytes = Vec::from(&bytes as &[u8]);
bytes.extend(extra);
let res = try_from(&bytes).unwrap();
assert_eq!((Length::Definite(usize::MAX), extra), res);
}
}
#[test]
fn try_from_overflow() {
let mut bytes: [u8; size_of::<usize>() + 2] = [0x00; size_of::<usize>() + 2];
bytes[0] = 0x80 + (size_of::<usize>() as u8) + 1;
bytes[1] = 0x01;
let e = try_from(&bytes).unwrap_err();
assert_eq!(Error::OverFlow, e);
let mut bytes = Vec::from(&bytes as &[u8]);
bytes.push(0xff);
let e = try_from(&bytes).unwrap_err();
assert_eq!(Error::OverFlow, e);
}
#[test]
fn try_from_redundant() {
{
let bytes: &[u8] = &[0x81, 0x00];
let e = try_from(bytes).unwrap_err();
assert_eq!(Error::RedundantBytes, e);
}
{
let bytes: &[u8] = &[0x82, 0x00, 0x01];
let e = try_from(bytes).unwrap_err();
assert_eq!(Error::RedundantBytes, e);
let bytes: &[u8] = &[0x82, 0x00, 0xff];
let e = try_from(bytes).unwrap_err();
assert_eq!(Error::RedundantBytes, e);
}
{
let mut bytes: [u8; size_of::<usize>() + 2] = [0xff; size_of::<usize>() + 2];
bytes[0] = 0x80 + (size_of::<usize>() as u8) + 1;
bytes[1] = 0x00;
let e = try_from(&bytes).unwrap_err();
assert_eq!(Error::RedundantBytes, e);
}
}
#[test]
fn try_from_unterminated() {
{
let bytes: &[u8] = &[0x82, 0x01];
let e = try_from(bytes).unwrap_err();
assert_eq!(Error::UnTerminatedBytes, e);
let bytes: &[u8] = &[0x82, 0xff];
let e = try_from(bytes).unwrap_err();
assert_eq!(Error::UnTerminatedBytes, e);
}
{
let bytes: &[u8] = &[0x83, 0x01, 0x00];
let e = try_from(bytes).unwrap_err();
assert_eq!(Error::UnTerminatedBytes, e);
let bytes: &[u8] = &[0x83, 0xff, 0xff];
let e = try_from(bytes).unwrap_err();
assert_eq!(Error::UnTerminatedBytes, e);
}
{
let mut bytes: [u8; size_of::<usize>() + 1] = [0xff; size_of::<usize>() + 1];
bytes[0] = 0x80 + (size_of::<usize>() as u8) + 1;
let e = try_from(&bytes).unwrap_err();
assert_eq!(Error::UnTerminatedBytes, e);
}
}
#[test]
fn to_bytes() {
let empty: &[u8] = &[];
{
let bytes = Length::Indefinite.to_bytes();
let length = try_from(bytes.as_ref()).unwrap();
assert_eq!((Length::Indefinite, empty), length);
}
for &len in &[0, 1, 0x7f, 0x80, 0xff, 0x0100, 0xffff, usize::MAX] {
let bytes = Length::Definite(len).to_bytes();
let length = try_from(bytes.as_ref()).unwrap();
assert_eq!((Length::Definite(len), empty), length);
}
}
}