Skip to content

Commit

Permalink
pedantic linting
Browse files Browse the repository at this point in the history
  • Loading branch information
TimLuq committed Aug 5, 2024
1 parent 77c112a commit c4426bb
Show file tree
Hide file tree
Showing 38 changed files with 3,005 additions and 1,747 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ description = "Representation of a byte slice that is either static, borrowed, o
license = "MIT OR LGPL-3.0-or-later"
repository = "https://github.com/TimLuq/bytedata/"
authors = ["TimLuq"]
categories = ["network-programming", "data-structures"]
keywords = ["arc", "buffers", "zero-copy", "io"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand Down
85 changes: 55 additions & 30 deletions src/byte_chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@ impl ByteChunk {
pub const LEN: usize = 14;

/// Create a `ByteChunk` from a slice.
#[inline]
#[must_use]
pub const fn from_slice(data: &[u8]) -> Self {
let len = data.len();
core::assert!(len <= Self::LEN, "chunk data too large");
let mut chunk = ByteChunk {
let mut chunk = Self {
#[allow(clippy::cast_possible_truncation)]
len: len as u8,
// SAFETY: `ByteChunk` with all zeros is a valid empty chunk.
data: unsafe { core::mem::zeroed() },
};
let mut i = 0;
Expand All @@ -30,10 +34,14 @@ impl ByteChunk {
}

/// Create a `ByteChunk` from a fixed-size array.
#[inline]
#[must_use]
pub const fn from_array<const L: usize>(data: &[u8; L]) -> Self {
core::assert!(L <= Self::LEN, "chunk data too large");
let mut chunk = ByteChunk {
let mut chunk = Self {
#[allow(clippy::cast_possible_truncation)]
len: L as u8,
// SAFETY: `ByteChunk` with all zeros is a valid empty chunk.
data: unsafe { core::mem::zeroed() },
};
let mut i = 0;
Expand All @@ -46,9 +54,11 @@ impl ByteChunk {

/// Create a `ByteChunk` from a fixed-size array.
#[inline]
#[must_use]
pub const fn from_byte(data: u8) -> Self {
let mut chunk: ByteChunk = ByteChunk {
let mut chunk: Self = Self {
len: 1,
// SAFETY: `ByteChunk` with all zeros is a valid empty chunk.
data: unsafe { core::mem::zeroed() },
};
chunk.data[0] = data;
Expand All @@ -57,96 +67,108 @@ impl ByteChunk {

/// Get the bytes of the `ByteChunk` as a slice.
#[inline]
#[must_use]
pub const fn as_slice(&self) -> &[u8] {
let len = self.len as usize;
if len == 0 {
return &[];
}
unsafe { core::slice::from_raw_parts(&self.data[0], len) }
// SAFETY: `len` is within bounds.
unsafe { core::slice::from_raw_parts(self.data.as_ptr(), len) }
}

/// Get the number bytes of the `ByteChunk`.
#[inline]
#[must_use]
pub const fn len(&self) -> usize {
self.len as usize
}

/// Check if the `ByteChunk` is empty.
#[inline]
#[must_use]
pub const fn is_empty(&self) -> bool {
self.len == 0
}

/// Slice the `ByteChunk` in place.
fn slice(&mut self, start: usize, end: usize) {
let len = self.len as usize;
if end > len || start > end {
panic!("ByteData: range out of bounds");
}
let curr_len = self.len as usize;
assert!(
end <= curr_len && start <= end,
"ByteData: range out of bounds"
);
#[allow(clippy::cast_possible_truncation)]
let len = (end - start) as u8;
self.len = len;
if len != 0 && start != 0 {
let len = len as usize;
let mut i = 0usize;
while i < len {
self.data[i] = self.data[start + i];
i += 1;
}
if len == 0 || start == 0 {
return;
}
let len = len as usize;
// SAFETY: `start` and `end` are within bounds.
let sorc = unsafe { self.data.as_ptr().add(start) };
let dest = self.data.as_mut_ptr();
// SAFETY: `sorc` and `dest` are valid pointers. They may however overlap for `len` bytes.
unsafe { core::ptr::copy(sorc, dest, len) };
}

/// Return as subslice of the `ByteChunk`.
#[inline]
#[must_use]
pub fn sliced<R: RangeBounds<usize> + SliceIndex<[u8], Output = [u8]>>(
&'_ self,
range: R,
) -> Self {
let start = match range.start_bound() {
core::ops::Bound::Included(&s) => s,
core::ops::Bound::Excluded(&s) => s + 1,
core::ops::Bound::Included(&start) => start,
core::ops::Bound::Excluded(&start) => start + 1,
core::ops::Bound::Unbounded => 0,
};
let end = match range.end_bound() {
core::ops::Bound::Included(&e) => e + 1,
core::ops::Bound::Excluded(&e) => e,
core::ops::Bound::Included(&end) => end + 1,
core::ops::Bound::Excluded(&end) => end,
core::ops::Bound::Unbounded => self.len as usize,
};
let mut r = *self;
Self::slice(&mut r, start, end);
r
let mut ret = *self;
Self::slice(&mut ret, start, end);
ret
}

/// Return as subslice of the `ByteChunk`.
#[inline]
#[must_use]
pub fn into_sliced<R: RangeBounds<usize> + SliceIndex<[u8], Output = [u8]>>(
mut self,
range: R,
) -> Self {
let start = match range.start_bound() {
core::ops::Bound::Included(&s) => s,
core::ops::Bound::Excluded(&s) => s + 1,
core::ops::Bound::Included(&start) => start,
core::ops::Bound::Excluded(&start) => start + 1,
core::ops::Bound::Unbounded => 0,
};
let end = match range.end_bound() {
core::ops::Bound::Included(&e) => e + 1,
core::ops::Bound::Excluded(&e) => e,
core::ops::Bound::Included(&end) => end + 1,
core::ops::Bound::Excluded(&end) => end,
core::ops::Bound::Unbounded => self.len as usize,
};
Self::slice(&mut self, start, end);
self
}

/// Slice the `ByteChunk` in place.
#[inline]
pub fn make_sliced<R: RangeBounds<usize> + SliceIndex<[u8], Output = [u8]>>(
&'_ mut self,
range: R,
) {
let start = match range.start_bound() {
core::ops::Bound::Included(&s) => s,
core::ops::Bound::Excluded(&s) => s + 1,
core::ops::Bound::Included(&start) => start,
core::ops::Bound::Excluded(&start) => start + 1,
core::ops::Bound::Unbounded => 0,
};
let end = match range.end_bound() {
core::ops::Bound::Included(&e) => e + 1,
core::ops::Bound::Excluded(&e) => e,
core::ops::Bound::Included(&end) => end + 1,
core::ops::Bound::Excluded(&end) => end,
core::ops::Bound::Unbounded => self.len as usize,
};
Self::slice(self, start, end);
Expand All @@ -156,11 +178,14 @@ impl ByteChunk {
impl Default for ByteChunk {
#[inline]
fn default() -> Self {
// SAFETY: `ByteChunk` with all zeros is a valid empty chunk.
unsafe { core::mem::zeroed() }
}
}

impl core::fmt::Debug for ByteChunk {
#[inline]
#[allow(clippy::min_ident_chars)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let rend = crate::ByteStringRender::from_slice(self.as_slice());
core::fmt::Debug::fmt(&rend, f)
Expand Down
112 changes: 92 additions & 20 deletions src/byte_string_render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,29 @@ pub struct ByteStringRender<'a>(&'a [u8]);
impl<'a> ByteStringRender<'a> {
/// Get the inner byte slice.
#[inline]
#[must_use]
pub const fn as_slice(&self) -> &'a [u8] {
self.0
}

/// Create a new `ByteStringRender` from a byte slice.
#[inline]
#[must_use]
pub const fn from_slice(slice: &'a [u8]) -> Self {
Self(slice)
}

/// Create a new `ByteStringRender` from a string slice.
#[inline]
#[must_use]
pub const fn from_str(slice: &'a str) -> Self {
Self(slice.as_bytes())
}

/// Create a new `ByteStringRender` from a byte slice reference.
#[inline]
pub fn from_ref(slice: &'a impl AsRef<[u8]>) -> Self {
#[must_use]
pub fn from_ref<B: AsRef<[u8]>>(slice: &'a B) -> Self {
Self(slice.as_ref())
}
}
Expand All @@ -51,34 +57,92 @@ impl<'a> From<&'a str> for ByteStringRender<'a> {
}
}

impl<'a> core::fmt::Debug for ByteStringRender<'a> {
impl core::fmt::Debug for ByteStringRender<'_> {
#[inline]
#[allow(clippy::min_ident_chars)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("b\"")?;
core::fmt::Display::fmt(self, f)?;
f.write_str("\"")
}
}

impl<'a> core::fmt::Display for ByteStringRender<'a> {
impl core::fmt::Display for ByteStringRender<'_> {
#[inline]
#[allow(clippy::min_ident_chars)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
for &b in self.0 {
match b {
for &by in self.0 {
match by {
b'\\' => f.write_str("\\\\")?,
b'"' => f.write_str("\\\"")?,
b'\n' => f.write_str("\\n")?,
b'\r' => f.write_str("\\r")?,
b'\t' => f.write_str("\\t")?,
b if (32..127).contains(&b) => {
f.write_str(unsafe { core::str::from_utf8_unchecked(&[b]) })?
by if (32..127).contains(&by) => {
let by = [by];
// SAFETY: `by` is ASCII-7.
let dat = unsafe { core::str::from_utf8_unchecked(&by) };
f.write_str(dat)?;
}
b => f.write_fmt(format_args!("\\x{:02x}", b))?,
by => f.write_fmt(format_args!("\\x{by:02x}"))?,
}
}
Ok(())
}
}

#[allow(clippy::redundant_pub_crate)]
pub(crate) fn lower_hex_slice(sl: &[u8], fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if let Some(w) = fmt.width() {
let mul = sl.len() << 1_u8;
if w > mul {
for _ in 0..w - mul {
core::fmt::Write::write_str(fmt, "0")?;
}
}
}
let mut i = 0;
while i < sl.len() {
write!(fmt, "{:02x}", sl[i])?;
i += 1;
}
Ok(())
}

impl core::fmt::LowerHex for ByteStringRender<'_> {
#[allow(clippy::min_ident_chars)]
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
lower_hex_slice(self.as_slice(), f)
}
}

#[allow(clippy::redundant_pub_crate)]
pub(crate) fn upper_hex_slice(sl: &[u8], fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if let Some(w) = fmt.width() {
let mul = sl.len() << 1_u8;
if w > mul {
for _ in 0..w - mul {
core::fmt::Write::write_str(fmt, "0")?;
}
}
}
let mut i = 0;
while i < sl.len() {
write!(fmt, "{:02X}", sl[i])?;
i += 1;
}
Ok(())
}

impl core::fmt::UpperHex for ByteStringRender<'_> {
#[allow(clippy::min_ident_chars)]
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
upper_hex_slice(self.as_slice(), f)
}
}

/// Helper wrapper to render a byte slice as a bytestring similar to [`core::ascii::escape_default`].
///
#[cfg_attr(feature = "alloc", doc = "```")]
Expand All @@ -101,6 +165,7 @@ where
&'a T: IntoIterator<Item = R>,
{
/// Create a new `MultiByteStringRender` from an iterator over byte slices.
#[inline]
pub const fn new(inner: &'a T) -> Self {
Self {
inner,
Expand All @@ -113,6 +178,8 @@ impl<'a, T, R: AsRef<[u8]>> core::fmt::Debug for MultiByteStringRender<'a, T, R>
where
&'a T: IntoIterator<Item = R>,
{
#[inline]
#[allow(clippy::min_ident_chars)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("b\"")?;
core::fmt::Display::fmt(self, f)?;
Expand All @@ -125,10 +192,11 @@ where
&'a T: IntoIterator<Item = R>,
{
#[inline]
#[allow(clippy::min_ident_chars)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
for b in self.inner.into_iter() {
let r = ByteStringRender::from_slice(b.as_ref());
core::fmt::Display::fmt(&r, f)?;
for by in self.inner {
let rend = ByteStringRender::from_slice(by.as_ref());
core::fmt::Display::fmt(&rend, f)?;
}
Ok(())
}
Expand All @@ -141,14 +209,18 @@ mod tests {

#[test]
fn test_byte_string_render() {
let data = b"Hello, World!";
let rendered = ByteStringRender::from_slice(data);
assert_eq!(alloc::format!("{}", &rendered), r#"Hello, World!"#);
assert_eq!(alloc::format!("{:?}", &rendered), r#"b"Hello, World!""#);

let data = b"Hello, \nWorld!";
let rendered = ByteStringRender::from_slice(data);
assert_eq!(alloc::format!("{}", &rendered), r#"Hello, \nWorld!"#);
assert_eq!(alloc::format!("{:?}", &rendered), r#"b"Hello, \nWorld!""#);
{
let data = b"Hello, World!";
let rendered = ByteStringRender::from_slice(data);
assert_eq!(alloc::format!("{}", &rendered), "Hello, World!");
assert_eq!(alloc::format!("{:?}", &rendered), r#"b"Hello, World!""#);
};

{
let data = b"Hello, \nWorld!";
let rendered = ByteStringRender::from_slice(data);
assert_eq!(alloc::format!("{}", &rendered), r"Hello, \nWorld!");
assert_eq!(alloc::format!("{:?}", &rendered), r#"b"Hello, \nWorld!""#);
};
}
}
Loading

0 comments on commit c4426bb

Please sign in to comment.