Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HeaderSection: Change slices to fixed-length arrays #329

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 108 additions & 145 deletions src/base/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,38 +79,25 @@ impl Header {
Self::default()
}

/// Creates a header reference from an octets slice of a message.
///
/// # Panics
///
/// This function panics if the slice is less than four octets long.
/// Creates a header from an octets array of a message.
#[must_use]
pub fn for_message_slice(s: &[u8]) -> &Header {
assert!(s.len() >= mem::size_of::<Header>());

// SAFETY: The pointer cast is sound because
// - Header has repr(transparent) and
// - the slice is large enough
unsafe { &*(s.as_ptr() as *const Header) }
pub fn from_array(array: [u8; 4]) -> Header {
Header { inner: array }
}

/// Creates a mutable header reference from an octets slice of a message.
///
/// # Panics
///
/// This function panics if the slice is less than four octets long.
pub fn for_message_slice_mut(s: &mut [u8]) -> &mut Header {
assert!(s.len() >= mem::size_of::<Header>());

// SAFETY: The pointer cast is sound because
// - Header has repr(transparent) and
// - the slice is large enough
unsafe { &mut *(s.as_mut_ptr() as *mut Header) }
/// Creates a mutable header reference from an octets array of a message.
pub fn for_array_mut(s: &mut [u8; 4]) -> &mut Header {
// SAFETY: The transmute is sound because
// - Header has #[repr(transparent)] and
// - we assert at compile time that the sizes are the same with this
// transmute which will get compiled away:
let _ = || unsafe { mem::transmute::<[u8; 4], Self>(*s) };
unsafe { mem::transmute(s) }
}

/// Returns a reference to the underlying octets slice.
#[must_use]
pub fn as_slice(&self) -> &[u8] {
pub fn as_array(&self) -> &[u8; 4] {
&self.inner
}
}
Expand Down Expand Up @@ -503,63 +490,36 @@ impl HeaderCounts {
Self::default()
}

/// Creates a header counts reference from the octets slice of a message.
///
/// The slice `message` mut be the whole message, i.e., start with the
/// bytes of the [`Header`](struct.Header.html).
///
/// # Panics
///
/// This function panics if the octets slice is shorter than 24 octets.
/// Creates a header counts from the octets array.
#[must_use]
pub fn for_message_slice(message: &[u8]) -> &Self {
assert!(message.len() >= mem::size_of::<HeaderSection>());

// SAFETY: The pointer cast is sound because
// - HeaderCounts has repr(transparent) and
// - the slice is large enough for a HeaderSection, which contains
// both a Header (which we trim) and a HeaderCounts.
unsafe {
&*((message[mem::size_of::<Header>()..].as_ptr())
as *const HeaderCounts)
}
pub fn from_array(array: [u8; 8]) -> Self {
Self { inner: array }
}

/// Creates a mutable counts reference from the octets slice of a message.
///
/// The slice `message` mut be the whole message, i.e., start with the
/// bytes of the [`Header`].
///
/// # Panics
///
/// This function panics if the octets slice is shorter than 24 octets.
pub fn for_message_slice_mut(message: &mut [u8]) -> &mut Self {
assert!(message.len() >= mem::size_of::<HeaderSection>());

// SAFETY: The pointer cast is sound because
// - HeaderCounts has repr(transparent) and
// - the slice is large enough for a HeaderSection, which contains
// both a Header (which we trim) and a HeaderCounts.
unsafe {
&mut *((message[mem::size_of::<Header>()..].as_mut_ptr())
as *mut HeaderCounts)
}
/// Creates a mutable counts reference from an octets array.
pub fn for_array_mut(message: &mut [u8; 8]) -> &mut Self {
// SAFETY: The transmute is sound because
// - Header has #[repr(transparent)] and
// - we assert at compile time that the sizes are the same with this
// transmute which will get compiled away:
let _ = || unsafe { mem::transmute::<[u8; 8], Self>(*message) };
unsafe { mem::transmute(message) }
}

/// Returns a reference to the raw octets slice of the header counts.
#[must_use]
pub fn as_slice(&self) -> &[u8] {
pub fn as_array(&self) -> &[u8; 8] {
&self.inner
}

/// Returns a mutable reference to the octets slice of the header counts.
pub fn as_slice_mut(&mut self) -> &mut [u8] {
pub fn as_array_mut(&mut self) -> &mut [u8; 8] {
&mut self.inner
}

/// Sets the counts to those from `counts`.
pub fn set(&mut self, counts: HeaderCounts) {
self.as_slice_mut().copy_from_slice(counts.as_slice())
*self.as_array_mut() = *counts.as_array()
}
}

Expand Down Expand Up @@ -825,30 +785,25 @@ impl HeaderSection {
Self::default()
}

/// Creates a reference from the octets slice of a message.
///
/// # Panics
///
/// This function panics if the octets slice is shorter than 12 octets.
/// Creates a reference from an octets array.
#[must_use]
pub fn for_message_slice(s: &[u8]) -> &HeaderSection {
assert!(s.len() >= mem::size_of::<HeaderSection>());
unsafe { &*(s.as_ptr() as *const HeaderSection) }
pub fn from_array(array: [u8; 12]) -> Self {
Self { inner: array }
}

/// Creates a mutable reference from the octets slice of a message.
///
/// # Panics
///
/// This function panics if the octets slice is shorter than 12 octets.
pub fn for_message_slice_mut(s: &mut [u8]) -> &mut HeaderSection {
assert!(s.len() >= mem::size_of::<HeaderSection>());
unsafe { &mut *(s.as_mut_ptr() as *mut HeaderSection) }
/// Creates a mutable reference from an octets array.
pub fn for_array_mut(s: &mut [u8; 12]) -> &mut HeaderSection {
// SAFETY: The transmute is sound because
// - Header has #[repr(transparent)] and
// - we assert at compile time that the sizes are the same with this
// transmute which will get compiled away:
let _ = || unsafe { mem::transmute::<[u8; 12], Self>(*s) };
unsafe { mem::transmute(s) }
}

/// Returns a reference to the underlying octets slice.
#[must_use]
pub fn as_slice(&self) -> &[u8] {
pub fn as_array(&self) -> &[u8; 12] {
&self.inner
}
}
Expand All @@ -858,24 +813,66 @@ impl HeaderSection {
impl HeaderSection {
/// Returns a reference to the header.
#[must_use]
pub fn header(&self) -> &Header {
Header::for_message_slice(&self.inner)
pub fn header(&self) -> Header {
type Chunk = [u8; 4];

// SAFETY: `unwrap` is fine because HeaderSection has
// #[repr(transparent)] and the condition below, which will get
// compiled away, holds. If it doesn't hold, there will be a compile
// error.
const _: () = assert!(
mem::size_of::<Chunk>() < mem::size_of::<HeaderSection>()
);

let chunk: Chunk = self.inner[0..4].try_into().unwrap();
Header::from_array(chunk)
}

/// Returns a mutable reference to the header.
pub fn header_mut(&mut self) -> &mut Header {
Header::for_message_slice_mut(&mut self.inner)
pub fn as_header_mut(&mut self) -> &mut Header {
type Chunk = [u8; 4];

// SAFETY: `unwrap` is fine because HeaderSection has
// #[repr(transparent)] and the condition below, which will get
// compiled away, holds. If it doesn't hold, there will be a compile
// error.
const _: () = assert!(
mem::size_of::<Chunk>() < mem::size_of::<HeaderSection>()
);
let chunk: &mut Chunk = self.inner[0..4].as_mut().try_into().unwrap();
Header::for_array_mut(chunk)
}

/// Returns a reference to the header counts.
#[must_use]
pub fn counts(&self) -> &HeaderCounts {
HeaderCounts::for_message_slice(&self.inner)
pub fn counts(&self) -> HeaderCounts {
type Chunk = [u8; 8];

// SAFETY: `unwrap` is fine because HeaderSection has
// #[repr(transparent)] and the condition below, which will get
// compiled away, holds. If it doesn't hold, there will be a compile
// error.
const _: () = assert!(
mem::size_of::<Chunk>() < mem::size_of::<HeaderSection>()
);
let chunk: Chunk = self.inner[4..12].try_into().unwrap();
HeaderCounts::from_array(chunk)
}

/// Returns a mutable reference to the header counts.
pub fn counts_mut(&mut self) -> &mut HeaderCounts {
HeaderCounts::for_message_slice_mut(&mut self.inner)
pub fn as_counts_mut(&mut self) -> &mut HeaderCounts {
type Chunk = [u8; 8];

// SAFETY: `unwrap` is fine because HeaderSection has
// #[repr(transparent)] and the condition below, which will get
// compiled away, holds. If it doesn't hold, there will be a compile
// error.
const _: () = assert!(
mem::size_of::<Chunk>() < mem::size_of::<HeaderSection>()
);
let chunk: &mut Chunk =
self.inner[4..12].as_mut().try_into().unwrap();
HeaderCounts::for_array_mut(chunk)
}
}

Expand All @@ -898,32 +895,6 @@ impl HeaderSection {
}
}

//--- AsRef and AsMut

impl AsRef<Header> for HeaderSection {
fn as_ref(&self) -> &Header {
self.header()
}
}

impl AsMut<Header> for HeaderSection {
fn as_mut(&mut self) -> &mut Header {
self.header_mut()
}
}

impl AsRef<HeaderCounts> for HeaderSection {
fn as_ref(&self) -> &HeaderCounts {
self.counts()
}
}

impl AsMut<HeaderCounts> for HeaderSection {
fn as_mut(&mut self) -> &mut HeaderCounts {
self.counts_mut()
}
}

//============ Error Types ===================================================

//------------ FlagsFromStrError --------------------------------------------
Expand Down Expand Up @@ -967,50 +938,42 @@ mod test {
fn for_slice() {
use std::vec::Vec;

let header = b"\x01\x02\x00\x00\x12\x34\x56\x78\x9a\xbc\xde\xf0";
let mut vec = Vec::from(&header[..]);
let mut header =
Vec::from(b"\x01\x02\x00\x00\x12\x34\x56\x78\x9a\xbc\xde\xf0");

let chunk: &[u8; 4] = header[0..4].try_into().unwrap();
assert_eq!(
Header::for_message_slice(header).as_slice(),
Header::from_array(*chunk).as_array(),
b"\x01\x02\x00\x00"
);

let chunk: &mut [u8; 4] = header[0..4].as_mut().try_into().unwrap();
assert_eq!(
Header::for_message_slice_mut(vec.as_mut()).as_slice(),
Header::for_array_mut(chunk).as_array(),
b"\x01\x02\x00\x00"
);

let chunk: &[u8; 8] = header[4..12].try_into().unwrap();
assert_eq!(
HeaderCounts::for_message_slice(header).as_slice(),
HeaderCounts::from_array(*chunk).as_array(),
b"\x12\x34\x56\x78\x9a\xbc\xde\xf0"
);

let chunk: &mut [u8; 8] = header[4..12].as_mut().try_into().unwrap();
assert_eq!(
HeaderCounts::for_message_slice_mut(vec.as_mut()).as_slice(),
HeaderCounts::for_array_mut(chunk).as_array(),
b"\x12\x34\x56\x78\x9a\xbc\xde\xf0"
);

let chunk: &[u8; 12] = header[..].try_into().unwrap();
assert_eq!(
HeaderSection::for_message_slice(header).as_slice(),
header
);
assert_eq!(
HeaderSection::for_message_slice_mut(vec.as_mut()).as_slice(),
HeaderSection::from_array(*chunk).as_array().as_slice(),
header
);
}

#[test]
#[should_panic]
fn short_header() {
let _ = Header::for_message_slice(b"134");
}

#[test]
#[should_panic]
fn short_header_counts() {
let _ = HeaderCounts::for_message_slice(b"12345678");
}

#[test]
#[should_panic]
fn short_header_section() {
let _ = HeaderSection::for_message_slice(b"1234");
let chunk: &mut [u8; 12] = header[..].as_mut().try_into().unwrap();
let section = *HeaderSection::for_array_mut(chunk).as_array();
assert_eq!(&section[..], header);
}

macro_rules! test_field {
Expand Down
Loading
Loading