use crate::{identifier_ref, length, ContentsRef, Der, Error, IdRef, Length};
use std::borrow::Borrow;
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct DerRef {
bytes: [u8],
}
impl DerRef {
pub const fn boolean(val: bool) -> &'static Self {
match val {
true => unsafe { Self::from_bytes_unchecked(&[0x01, 0x01, 0xff]) },
false => unsafe { Self::from_bytes_unchecked(&[0x01, 0x01, 0x00]) },
}
}
pub fn parse<'a>(bytes: &mut &'a [u8]) -> Result<&'a Self, Error> {
let init_bytes = *bytes;
Self::do_parse(bytes)?;
let total_len = init_bytes.len() - bytes.len();
let read = &init_bytes[..total_len];
unsafe { Ok(Self::from_bytes_unchecked(read)) }
}
pub fn parse_mut<'a>(bytes: &mut &'a mut [u8]) -> Result<&'a mut Self, Error> {
let read_bytes = {
let mut readable: &[u8] = *bytes;
Self::do_parse(&mut readable)?;
bytes.len() - readable.len()
};
unsafe {
let init_ptr = bytes.as_mut_ptr();
let left_bytes = bytes.len() - read_bytes;
*bytes = std::slice::from_raw_parts_mut(init_ptr.add(read_bytes), left_bytes);
let read = std::slice::from_raw_parts_mut(init_ptr, read_bytes);
Ok(Self::from_mut_bytes_unchecked(read))
}
}
fn do_parse(readable: &mut &[u8]) -> Result<(), Error> {
let mut writeable = std::io::sink();
let length = match unsafe { crate::misc::parse_id_length(readable, &mut writeable)? } {
Length::Indefinite => return Err(Error::IndefiniteLength),
Length::Definite(length) => length,
};
if readable.len() < length {
Err(Error::UnterminatedBytes)
} else {
*readable = &readable[length..];
Ok(())
}
}
pub const unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
std::mem::transmute(bytes)
}
pub unsafe fn from_mut_bytes_unchecked(bytes: &mut [u8]) -> &mut Self {
std::mem::transmute(bytes)
}
pub fn id(&self) -> &IdRef {
unsafe { identifier_ref::parse_id_unchecked(&mut &self.bytes) }
}
pub fn mut_id(&mut self) -> &mut IdRef {
self.disassemble_mut().0
}
pub fn length(&self) -> Length {
self.disassemble().1
}
pub fn contents(&self) -> &ContentsRef {
self.disassemble().2
}
pub fn mut_contents(&mut self) -> &mut ContentsRef {
self.disassemble_mut().2
}
pub fn disassemble(&self) -> (&IdRef, Length, &ContentsRef) {
let mut bytes = &self.bytes;
let id = unsafe { identifier_ref::parse_id_unchecked(&mut bytes) };
let length = unsafe { length::parse_length_unchecked(&mut bytes) };
let contents = bytes.into();
(id, length, contents)
}
pub fn disassemble_mut(&mut self) -> (&mut IdRef, Length, &mut ContentsRef) {
let (id, length, contents) = self.disassemble();
let id_ptr = id as *const IdRef;
let id_ptr = id_ptr as *mut IdRef;
let contents_ptr = contents as *const ContentsRef;
let contents_ptr = contents_ptr as *mut ContentsRef;
unsafe { (&mut *id_ptr, length, &mut *contents_ptr) }
}
}
impl AsRef<[u8]> for DerRef {
fn as_ref(&self) -> &[u8] {
&self.bytes
}
}
impl ToOwned for DerRef {
type Owned = Der;
fn to_owned(&self) -> Self::Owned {
unsafe { Der::from_bytes_unchecked(self.as_ref()) }
}
}
impl<T> PartialEq<T> for DerRef
where
T: Borrow<DerRef>,
{
fn eq(&self, other: &T) -> bool {
self == other.borrow()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_single() {
let bytes: Vec<u8> = (0..=u8::MAX).collect();
for i in 0..bytes.len() {
let der = Der::from(&bytes[..i]);
let mut bytes: &[u8] = der.as_ref();
let parsed = DerRef::parse(&mut bytes).unwrap();
assert_eq!(der, parsed);
assert_eq!(bytes.len(), 0);
}
}
#[test]
fn parse_recursive() {
let bytes: Vec<u8> = (0..=u8::MAX).collect();
for i in 0..bytes.len() {
let inner = Der::from(&bytes[..i]);
let der = Der::new(IdRef::sequence(), (inner.as_ref() as &[u8]).into());
let mut bytes: &[u8] = der.as_ref();
let parsed = DerRef::parse(&mut bytes).unwrap();
assert_eq!(der, parsed);
assert_eq!(bytes.len(), 0);
}
}
}