From d4e92c9e6d2c42e6c8a9a0ed9ebe71c7ba715ba2 Mon Sep 17 00:00:00 2001 From: Austin Henriksen Date: Tue, 28 Jul 2026 15:50:27 -0400 Subject: [PATCH 1/3] Updated folder structure of the 'slice-codec' crate to be more modular. --- slice-codec/src/buffer/slice.rs | 454 ------------------ slice-codec/src/{ => decoding}/decode_from.rs | 4 +- slice-codec/src/{ => decoding}/decoder.rs | 4 +- slice-codec/src/{ => decoding}/decoding.rs | 6 +- slice-codec/src/decoding/mod.rs | 7 + slice-codec/src/{ => encoding}/encode_into.rs | 4 +- slice-codec/src/{ => encoding}/encoder.rs | 4 +- slice-codec/src/{ => encoding}/encoding.rs | 6 +- slice-codec/src/encoding/mod.rs | 7 + slice-codec/src/input_source/mod.rs | 39 ++ .../src/input_source/slice_input_source.rs | 204 ++++++++ slice-codec/src/lib.rs | 16 +- .../src/{buffer => output_target}/mod.rs | 38 +- .../src/output_target/slice_output_target.rs | 254 ++++++++++ .../vec_output_target.rs} | 20 +- slice-codec/tests/encoding_tests.rs | 13 +- slicec/src/definition_types.rs | 3 +- 17 files changed, 558 insertions(+), 525 deletions(-) delete mode 100644 slice-codec/src/buffer/slice.rs rename slice-codec/src/{ => decoding}/decode_from.rs (97%) rename slice-codec/src/{ => decoding}/decoder.rs (93%) rename slice-codec/src/{ => decoding}/decoding.rs (99%) create mode 100644 slice-codec/src/decoding/mod.rs rename slice-codec/src/{ => encoding}/encode_into.rs (98%) rename slice-codec/src/{ => encoding}/encoder.rs (92%) rename slice-codec/src/{ => encoding}/encoding.rs (98%) create mode 100644 slice-codec/src/encoding/mod.rs create mode 100644 slice-codec/src/input_source/mod.rs create mode 100644 slice-codec/src/input_source/slice_input_source.rs rename slice-codec/src/{buffer => output_target}/mod.rs (68%) create mode 100644 slice-codec/src/output_target/slice_output_target.rs rename slice-codec/src/{buffer/vec.rs => output_target/vec_output_target.rs} (90%) diff --git a/slice-codec/src/buffer/slice.rs b/slice-codec/src/buffer/slice.rs deleted file mode 100644 index d78bd36f..00000000 --- a/slice-codec/src/buffer/slice.rs +++ /dev/null @@ -1,454 +0,0 @@ -// Copyright (c) ZeroC, Inc. - -//! TODO maybe write a comment explaining this module? - -use super::*; -use crate::{ErrorKind, Result}; -use core::borrow::Borrow; -use core::{debug_assert, debug_assert_eq}; - -/// A wrapper around a `&[u8]` that implements [`InputSource`]. -#[derive(Debug)] -pub struct SliceInputSource<'a> { - /// The underlying buffer that this type wraps. - buffer: &'a [u8], - /// Tracks the current position in the buffer that is being read from. - pos: usize, -} - -impl<'a> SliceInputSource<'a> { - /// Checks whether there are at least `requested` unread bytes left in the buffer. - /// If there are, this returns `Ok`, and if there aren't this returns an [`ErrorKind::UnexpectedEob`] error. - /// - /// This function is only used internally to ensure a particular read operation is safe to attempt. - fn does_buffer_have_at_least(&self, requested: usize) -> Result<()> { - let remaining = self.remaining(); - if remaining < requested { - let error = ErrorKind::UnexpectedEob { requested, remaining }; - Err(error.into()) - } else { - Ok(()) - } - } -} - -impl InputSource for SliceInputSource<'_> { - fn remaining(&self) -> usize { - self.buffer.len() - self.pos - } - - fn peek_byte(&mut self) -> Result { - self.does_buffer_have_at_least(1)?; - - // SAFETY: the necessary bounds checking is performed by the above function call. - unsafe { - debug_assert!(self.buffer.get(self.pos).is_some()); - Ok(*self.buffer.get_unchecked(self.pos)) - } - } - - fn read_byte(&mut self) -> Result { - let byte = self.peek_byte()?; - self.pos += 1; - Ok(byte) - } - - fn read_bytes_exact(&mut self) -> Result<&[u8; N]> { - let byte_slice = self.read_byte_slice_exact(N)?; - - // SAFETY: `read_byte_slice_exact` is guaranteed to return exactly 'N' bytes, which means it's safe to - // convert, since `&[u8; N]` has the same layout as an `&[u8]` over 'N' bytes. - let byte_array = unsafe { - debug_assert_eq!(byte_slice.len(), N); - byte_slice.try_into().unwrap_unchecked() - }; - - Ok(byte_array) - } - - fn read_byte_slice_exact(&mut self, count: usize) -> Result<&[u8]> { - self.does_buffer_have_at_least(count)?; - - // SAFETY: the necessary bounds checking is performed by the above function call. - let byte_slice = unsafe { - let end = self.pos + count; - debug_assert!(self.buffer.get(self.pos..end).is_some()); - self.buffer.get_unchecked(self.pos..end) - }; - self.pos += count; - Ok(byte_slice) - } - - fn read_bytes_into_exact(&mut self, dst: &mut [u8]) -> Result<()> { - let src = self.read_byte_slice_exact(dst.len())?; - - // SAFETY: `read_byte_slice_exact` is guaranteed to return exactly `dst.len()` bytes, so there is enough space - // in `dst` to write these bytes, and we know the slices cannot overlap because `dst` is mutably borrowed, - // which guarantees exclusive access. - unsafe { - debug_assert_eq!(src.len(), dst.len()); - core::ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), dst.len()); - Ok(()) - } - } -} - -impl<'a, T> From<&'a T> for SliceInputSource<'a> -where - T: Borrow<[u8]> + ?Sized, -{ - /// Creates a new [`SliceInputSource`] that wraps the provided buffer. - fn from(value: &'a T) -> Self { - Self { - buffer: value.borrow(), - pos: 0, - } - } -} - -// Allows users to create a [`Decoder`] directly from a slice, -// without needing to construct an intermediate [`SliceInputSource`]. -impl<'a, T> From for crate::decoder::Decoder> -where - T: Into>, -{ - fn from(value: T) -> Self { - crate::decoder::Decoder::new(value.into()) - } -} - -/// A wrapper around a `&mut [u8]` that implements [`OutputTarget`]. -#[derive(Debug)] -pub struct SliceOutputTarget<'a> { - /// The underlying buffer that this type wraps. - buffer: &'a mut [u8], - /// Tracks the current position in the buffer that is being written to. - pos: usize, -} - -impl<'a> SliceOutputTarget<'a> { - /// Checks whether there are at least `requested` unwritten bytes left in the buffer. - /// If there are, this returns `Ok`, and if there aren't this returns an [`ErrorKind::UnexpectedEob`] error. - /// - /// This function is only used internally to ensure a particular write operation is safe to attempt. - fn does_buffer_have_at_least(&self, requested: usize) -> Result<()> { - let remaining = self.remaining(); - if remaining < requested { - let error = ErrorKind::UnexpectedEob { requested, remaining }; - Err(error.into()) - } else { - Ok(()) - } - } -} - -impl OutputTarget for SliceOutputTarget<'_> { - fn remaining(&self) -> usize { - self.buffer.len() - self.pos - } - - fn write_byte(&mut self, byte: u8) -> Result<()> { - self.does_buffer_have_at_least(1)?; - - // SAFETY: the above function call guarantees there's enough space in `self.buffer` to write a single byte. - unsafe { - debug_assert!(self.buffer.get_mut(self.pos).is_some()); - *self.buffer.get_unchecked_mut(self.pos) = byte; - self.pos += 1; - Ok(()) - } - } - - fn write_bytes_exact(&mut self, bytes: &[u8]) -> Result<()> { - let count = bytes.len(); - self.does_buffer_have_at_least(count)?; - - // SAFETY: the above function call guarantees there's enough space in `self.buffer` to write `bytes`, - // and we know the slices cannot overlap because the mutable borrow of `self` guarantees exclusive access. - unsafe { - let end = self.pos + count; - debug_assert!(self.buffer.get_mut(self.pos..end).is_some()); - let target_slice = self.buffer.get_unchecked_mut(self.pos..end); - debug_assert_eq!(target_slice.len(), count); - - core::ptr::copy_nonoverlapping(bytes.as_ptr(), target_slice.as_mut_ptr(), count); - self.pos = end; - Ok(()) - } - } - - fn write_bytes_into_reserved_exact(&mut self, reservation: &mut Reservation, bytes: &[u8]) -> Result<()> { - // Get a mutable slice of the buffer - one that corresponds to the reserved range. - let Some(reserved_slice) = self.buffer.get_mut(reservation.range()) else { - let error = ErrorKind::InvalidReservation { - buffer_len: self.buffer.len(), - reserved_range: reservation.range(), - }; - return Err(error.into()); - }; - - // Ensure there's enough space remaining in the reservation. - if reserved_slice.len() < bytes.len() { - let error = ErrorKind::UnexpectedEob { - requested: bytes.len(), - remaining: reserved_slice.len(), - }; - return Err(error.into()); - } - - // SAFETY: we just checked that there's enough space in `reserved_slice` to write `bytes`, - // and we know the slices cannot overlap because the mutable borrow of `self` guarantees exclusive access. - unsafe { - core::ptr::copy_nonoverlapping(bytes.as_ptr(), reserved_slice.as_mut_ptr(), bytes.len()); - reservation.0.start += bytes.len(); - Ok(()) - } - } - - fn reserve_space(&mut self, count: usize) -> Result { - self.does_buffer_have_at_least(count)?; - - self.pos += count; - Ok(Reservation((self.pos - count)..self.pos)) - } -} - -impl<'a> From<&'a mut [u8]> for SliceOutputTarget<'a> { - /// Creates a new [`SliceOutputTarget`] that wraps the provided buffer. - fn from(value: &'a mut [u8]) -> Self { - Self { buffer: value, pos: 0 } - } -} - -impl<'a, const N: usize> From<&'a mut [u8; N]> for SliceOutputTarget<'a> { - /// Creates a new [`SliceOutputTarget`] that wraps the provided array. - fn from(value: &'a mut [u8; N]) -> Self { - Self { - buffer: value.as_mut_slice(), - pos: 0, - } - } -} - -// Allows users to create an [`Encoder`] directly from a slice, -// without needing to construct an intermediate [`SliceOutputTarget`]. -impl<'a, T> From for crate::encoder::Encoder> -where - T: Into>, -{ - fn from(value: T) -> Self { - crate::encoder::Encoder::new(value.into()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - mod slice_input_source { - use super::*; - - /// Verifies that [`does_buffer_have_at_least`] returns the correct number of remaining bytes in the buffer - /// when the remaining bytes number are greater than or equal to the number of requested bytes. - #[test] - fn does_buffer_has_at_least_returns_ok() { - // Arrange - let buffer = [115, 108, 105, 99, 101]; - let source = SliceInputSource::from(&buffer); - - // Act - let result = source.does_buffer_have_at_least(5); - - // Assert - assert!(result.is_ok()); - } - - /// Verifies that [`does_buffer_have_at_least`] returns an error when the remaining bytes number are less than - /// the number of requested bytes. - #[test] - fn does_buffer_have_at_least_returns_error() { - // Arrange - let source = SliceInputSource::from(&[115, 108, 105, 99, 101]); - - // Act - let result = source.does_buffer_have_at_least(6); - - // Assert - assert!(result.is_err()); - assert!(matches!(result.unwrap_err().kind(), ErrorKind::UnexpectedEob { - requested: 6, - remaining: 5 - })); - } - - /// Verifies that [`peek_byte`] returns the correct byte from the buffer without consuming it. - #[test] - fn peek_byte_returns_correct_byte() { - // Arrange - let mut source = SliceInputSource::from(&[115, 108, 105, 99, 101]); - - // Act - let result = source.peek_byte(); - - // Assert - assert!(result.is_ok()); - assert_eq!(result.unwrap(), 115); - assert_eq!(source.pos, 0); - assert_eq!(source.remaining(), 5); - } - - /// Verifies that [`read_byte`] returns the correct byte from the buffer and consumes it. - #[test] - fn read_byte_returns_correct_byte() { - // Arrange - let mut source = SliceInputSource::from(&[115, 108, 105, 99, 101]); - - // Act - let result = source.read_byte(); - - // Assert - assert!(result.is_ok()); - assert_eq!(result.unwrap(), 115); - assert_eq!(source.pos, 1); - assert_eq!(source.remaining(), 4); - } - - /// Verifies that [`read_bytes_exact`] returns the correct number of bytes from the buffer and consumes them. - #[test] - fn read_bytes_exact_returns_correct_bytes() { - // Arrange - let mut source = SliceInputSource::from(&[115, 108, 105, 99, 101]); - - // Act - let result = source.read_bytes_exact::<3>(); - - // Assert - assert!(result.is_ok()); - assert_eq!(result.unwrap(), &[115, 108, 105]); - assert_eq!(source.pos, 3); - assert_eq!(source.remaining(), 2); - } - } - - mod slice_output_target { - - use super::*; - - /// Verifies that [`does_buffer_have_at_least`] returns the correct number of remaining bytes in the buffer - /// when the remaining bytes number are greater than or equal to the number of requested bytes. - #[test] - fn does_buffer_has_at_least_returns_ok() { - // Arrange - let mut buffer = [115, 108, 105, 99, 101]; - let target = SliceOutputTarget::from(buffer.as_mut_slice()); - - // Act - let result = target.does_buffer_have_at_least(5); - - // Assert - assert!(result.is_ok()); - } - - /// Verifies that [`does_buffer_have_at_least`] returns an error when the remaining bytes number are less than - /// the number of requested bytes. - #[test] - fn does_buffer_have_at_least_returns_error() { - // Arrange - let mut buffer = [115, 108, 105, 99, 101]; - let target = SliceOutputTarget::from(buffer.as_mut_slice()); - - // Act - let result = target.does_buffer_have_at_least(6); - - // Assert - assert!(result.is_err()); - assert!(matches!(result.unwrap_err().kind(), ErrorKind::UnexpectedEob { - requested: 6, - remaining: 5 - })); - } - - /// Verifies that [`write_byte`] writes the correct byte to the buffer and advances the position. - #[test] - fn write_byte_writes_correct_byte() { - // Arrange - let mut buffer = [0; 5]; - let mut target = SliceOutputTarget::from(buffer.as_mut_slice()); - - // Act - let result = target.write_byte(115); - - // Assert - assert!(result.is_ok()); - assert_eq!(target.buffer, [115, 0, 0, 0, 0]); - assert_eq!(target.pos, 1); - assert_eq!(target.remaining(), 4); - } - - /// Verifies that [`write_bytes_exact`] writes the correct bytes to the buffer and advances the position. - #[test] - fn write_bytes_exact_writes_correct_bytes() { - // Arrange - let mut buffer = [0; 5]; - let mut target = SliceOutputTarget::from(buffer.as_mut_slice()); - - // Act - let result = target.write_bytes_exact(&[115, 108, 105, 99, 101]); - - // Assert - assert!(result.is_ok()); - assert_eq!(target.buffer, [115, 108, 105, 99, 101]); - assert_eq!(target.pos, 5); - assert_eq!(target.remaining(), 0); - } - - /// Verifies that [`reserve_space`] reserves the correct number of bytes in the buffer and advances the - /// position past the reserved space so that the next write operation will not write into the reserved space. - #[test] - fn reserve_space_reserves_correct_space() { - // Arrange - let mut buffer = [0; 5]; - let mut target = SliceOutputTarget::from(buffer.as_mut_slice()); - - // Act - let reserve_result = target.reserve_space(3); - let write_result = target.write_byte(99); - - // Assert - assert!(reserve_result.is_ok()); - assert!(write_result.is_ok()); - - assert_eq!(reserve_result.unwrap().0, 0..3); - assert_eq!(target.pos, 4); - assert_eq!(target.remaining(), 1); - assert_eq!(target.buffer, [0, 0, 0, 99, 0]); - } - - /// Verifies that [`write_bytes_into_reserved_exact`] writes the correct bytes to the reserved space in the - /// buffer and does not advance the position past the reserved space. - #[test] - fn write_bytes_into_reserved_exact_writes_correct_bytes() { - // Arrange - let mut buffer = [0; 5]; - let mut target = SliceOutputTarget::from(buffer.as_mut_slice()); - - // Should advance the position to 3. - let mut reservation = target.reserve_space(3).unwrap(); - - // Write a byte to ensure the position is advanced. - let _ = target.write_bytes_exact(&[99]); - - // Act - let result = target.write_bytes_into_reserved_exact(&mut reservation, &[115, 108, 105]); - - // Write a byte to ensure the position was not advanced. - let _ = target.write_byte(101); - - // Assert - assert!(result.is_ok()); - assert_eq!(target.buffer, [115, 108, 105, 99, 101]); - assert_eq!(target.pos, 5); - assert_eq!(target.remaining(), 0); - } - } -} diff --git a/slice-codec/src/decode_from.rs b/slice-codec/src/decoding/decode_from.rs similarity index 97% rename from slice-codec/src/decode_from.rs rename to slice-codec/src/decoding/decode_from.rs index b231cc0b..561bec20 100644 --- a/slice-codec/src/decode_from.rs +++ b/slice-codec/src/decoding/decode_from.rs @@ -1,7 +1,7 @@ // Copyright (c) ZeroC, Inc. -use crate::buffer::InputSource; -use crate::decoder::Decoder; +use super::decoder::Decoder; +use crate::input_source::InputSource; use crate::Result; /// TODO diff --git a/slice-codec/src/decoder.rs b/slice-codec/src/decoding/decoder.rs similarity index 93% rename from slice-codec/src/decoder.rs rename to slice-codec/src/decoding/decoder.rs index edfcbc74..228185f0 100644 --- a/slice-codec/src/decoder.rs +++ b/slice-codec/src/decoding/decoder.rs @@ -1,7 +1,7 @@ // Copyright (c) ZeroC, Inc. -use crate::buffer::InputSource; -use crate::decode_from::DecodeFrom; +use super::decode_from::DecodeFrom; +use crate::input_source::InputSource; use crate::Result; use core::ops::{Deref, DerefMut}; diff --git a/slice-codec/src/decoding.rs b/slice-codec/src/decoding/decoding.rs similarity index 99% rename from slice-codec/src/decoding.rs rename to slice-codec/src/decoding/decoding.rs index 87907836..875b4192 100644 --- a/slice-codec/src/decoding.rs +++ b/slice-codec/src/decoding/decoding.rs @@ -1,8 +1,8 @@ // Copyright (c) ZeroC, Inc. -use crate::buffer::InputSource; -use crate::decode_from::*; -use crate::decoder::Decoder; +use super::decode_from::*; +use super::decoder::Decoder; +use crate::input_source::InputSource; use crate::{Error, InvalidDataErrorKind, Result}; // We only support `String`, `Vec`, and `BTreeMap` if the `alloc` crate is available through the `alloc` feature flag. diff --git a/slice-codec/src/decoding/mod.rs b/slice-codec/src/decoding/mod.rs new file mode 100644 index 00000000..43e3edc7 --- /dev/null +++ b/slice-codec/src/decoding/mod.rs @@ -0,0 +1,7 @@ +// Copyright (c) ZeroC, Inc. + +pub mod decode_from; +pub mod decoder; + +// This module is private because it doesn't export any types, just implementations. +mod decoding; diff --git a/slice-codec/src/encode_into.rs b/slice-codec/src/encoding/encode_into.rs similarity index 98% rename from slice-codec/src/encode_into.rs rename to slice-codec/src/encoding/encode_into.rs index feee7bbf..d58b5c0d 100644 --- a/slice-codec/src/encode_into.rs +++ b/slice-codec/src/encoding/encode_into.rs @@ -1,7 +1,7 @@ // Copyright (c) ZeroC, Inc. -use crate::buffer::OutputTarget; -use crate::encoder::Encoder; +use super::encoder::Encoder; +use crate::output_target::OutputTarget; use crate::Result; /// TODO diff --git a/slice-codec/src/encoder.rs b/slice-codec/src/encoding/encoder.rs similarity index 92% rename from slice-codec/src/encoder.rs rename to slice-codec/src/encoding/encoder.rs index 085fd170..7157858b 100644 --- a/slice-codec/src/encoder.rs +++ b/slice-codec/src/encoding/encoder.rs @@ -1,7 +1,7 @@ // Copyright (c) ZeroC, Inc. -use crate::buffer::OutputTarget; -use crate::encode_into::EncodeInto; +use super::encode_into::EncodeInto; +use crate::output_target::OutputTarget; use crate::Result; use core::ops::{Deref, DerefMut}; diff --git a/slice-codec/src/encoding.rs b/slice-codec/src/encoding/encoding.rs similarity index 98% rename from slice-codec/src/encoding.rs rename to slice-codec/src/encoding/encoding.rs index 9f93d36d..ebf66dec 100644 --- a/slice-codec/src/encoding.rs +++ b/slice-codec/src/encoding/encoding.rs @@ -1,8 +1,8 @@ // Copyright (c) ZeroC, Inc. -use crate::buffer::OutputTarget; -use crate::encode_into::*; -use crate::encoder::Encoder; +use super::encode_into::*; +use super::encoder::Encoder; +use crate::output_target::OutputTarget; use crate::{Error, InvalidDataErrorKind, Result, VARINT62_MAX, VARINT62_MIN, VARUINT62_MAX, VARUINT62_MIN}; // We only support 'owned' sequence/dictionary types if the `alloc` crate is available through the `alloc` feature flag. diff --git a/slice-codec/src/encoding/mod.rs b/slice-codec/src/encoding/mod.rs new file mode 100644 index 00000000..f6d98871 --- /dev/null +++ b/slice-codec/src/encoding/mod.rs @@ -0,0 +1,7 @@ +// Copyright (c) ZeroC, Inc. + +pub mod encode_into; +pub mod encoder; + +// This module is private because it doesn't export any types, just implementations. +mod encoding; diff --git a/slice-codec/src/input_source/mod.rs b/slice-codec/src/input_source/mod.rs new file mode 100644 index 00000000..1903d369 --- /dev/null +++ b/slice-codec/src/input_source/mod.rs @@ -0,0 +1,39 @@ +// Copyright (c) ZeroC, Inc. + +//! TODO maybe write a comment explaining this module? + +mod slice_input_source; +pub use slice_input_source::*; + +use crate::Result; + +/// A trait for types that can be read from by a [Slice decoder](crate::decoder::Decoder). +pub trait InputSource { + /// Returns the number of unread bytes currently remaining in the source. + fn remaining(&self) -> usize; + + /// Returns the next byte available from this source without consuming it. + /// + /// If there are no more bytes available from this source, an [`UnexpectedEob`] error is returned instead. + /// + /// [`UnexpectedEob`]: crate::ErrorKind::UnexpectedEob + fn peek_byte(&mut self) -> Result; + + /// Returns the next byte available from this source, and advances past it (consuming it). + /// + /// If there are no more bytes available from this source, an [`UnexpectedEob`] error is returned instead. + /// + /// [`UnexpectedEob`]: crate::ErrorKind::UnexpectedEob + fn read_byte(&mut self) -> Result; + + // TODO remove these functions after adding `advance_by` and the low-level required API functions. + fn read_bytes_exact(&mut self) -> Result<&[u8; N]>; + fn read_byte_slice_exact(&mut self, count: usize) -> Result<&[u8]>; + + /// Reads bytes from this source into the provided buffer, and advances past them (consuming them). + /// + /// This function reads exactly `dest.len()`-many bytes, or if it's unable to, returns an error instead. + /// If such an error occurs, no guarantees are made about how many bytes were read from the source, except that it + /// is less than `dest.len()`. + fn read_bytes_into_exact(&mut self, dest: &mut [u8]) -> Result<()>; +} diff --git a/slice-codec/src/input_source/slice_input_source.rs b/slice-codec/src/input_source/slice_input_source.rs new file mode 100644 index 00000000..3feccfcf --- /dev/null +++ b/slice-codec/src/input_source/slice_input_source.rs @@ -0,0 +1,204 @@ +// Copyright (c) ZeroC, Inc. + +//! TODO maybe write a comment explaining this module? + +use super::*; +use crate::{ErrorKind, Result}; +use core::borrow::Borrow; +use core::{debug_assert, debug_assert_eq}; + +/// A wrapper around a `&[u8]` that implements [`InputSource`]. +#[derive(Debug)] +pub struct SliceInputSource<'a> { + /// The underlying buffer that this type wraps. + buffer: &'a [u8], + /// Tracks the current position in the buffer that is being read from. + pos: usize, +} + +impl<'a> SliceInputSource<'a> { + /// Checks whether there are at least `requested` unread bytes left in the buffer. + /// If there are, this returns `Ok`, and if there aren't this returns an [`ErrorKind::UnexpectedEob`] error. + /// + /// This function is only used internally to ensure a particular read operation is safe to attempt. + fn does_buffer_have_at_least(&self, requested: usize) -> Result<()> { + let remaining = self.remaining(); + if remaining < requested { + let error = ErrorKind::UnexpectedEob { requested, remaining }; + Err(error.into()) + } else { + Ok(()) + } + } +} + +impl InputSource for SliceInputSource<'_> { + fn remaining(&self) -> usize { + self.buffer.len() - self.pos + } + + fn peek_byte(&mut self) -> Result { + self.does_buffer_have_at_least(1)?; + + // SAFETY: the necessary bounds checking is performed by the above function call. + unsafe { + debug_assert!(self.buffer.get(self.pos).is_some()); + Ok(*self.buffer.get_unchecked(self.pos)) + } + } + + fn read_byte(&mut self) -> Result { + let byte = self.peek_byte()?; + self.pos += 1; + Ok(byte) + } + + fn read_bytes_exact(&mut self) -> Result<&[u8; N]> { + let byte_slice = self.read_byte_slice_exact(N)?; + + // SAFETY: `read_byte_slice_exact` is guaranteed to return exactly 'N' bytes, which means it's safe to + // convert, since `&[u8; N]` has the same layout as an `&[u8]` over 'N' bytes. + let byte_array = unsafe { + debug_assert_eq!(byte_slice.len(), N); + byte_slice.try_into().unwrap_unchecked() + }; + + Ok(byte_array) + } + + fn read_byte_slice_exact(&mut self, count: usize) -> Result<&[u8]> { + self.does_buffer_have_at_least(count)?; + + // SAFETY: the necessary bounds checking is performed by the above function call. + let byte_slice = unsafe { + let end = self.pos + count; + debug_assert!(self.buffer.get(self.pos..end).is_some()); + self.buffer.get_unchecked(self.pos..end) + }; + self.pos += count; + Ok(byte_slice) + } + + fn read_bytes_into_exact(&mut self, dst: &mut [u8]) -> Result<()> { + let src = self.read_byte_slice_exact(dst.len())?; + + // SAFETY: `read_byte_slice_exact` is guaranteed to return exactly `dst.len()` bytes, so there is enough space + // in `dst` to write these bytes, and we know the slices cannot overlap because `dst` is mutably borrowed, + // which guarantees exclusive access. + unsafe { + debug_assert_eq!(src.len(), dst.len()); + core::ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), dst.len()); + Ok(()) + } + } +} + +impl<'a, T> From<&'a T> for SliceInputSource<'a> +where + T: Borrow<[u8]> + ?Sized, +{ + /// Creates a new [`SliceInputSource`] that wraps the provided buffer. + fn from(value: &'a T) -> Self { + Self { + buffer: value.borrow(), + pos: 0, + } + } +} + +// Allows users to create a [`Decoder`] directly from a slice, +// without needing to construct an intermediate [`SliceInputSource`]. +impl<'a, T> From for crate::decoding::decoder::Decoder> +where + T: Into>, +{ + fn from(value: T) -> Self { + crate::decoding::decoder::Decoder::new(value.into()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Verifies that [`does_buffer_have_at_least`] returns the correct number of remaining bytes in the buffer + /// when the remaining bytes number are greater than or equal to the number of requested bytes. + #[test] + fn does_buffer_has_at_least_returns_ok() { + // Arrange + let buffer = [115, 108, 105, 99, 101]; + let source = SliceInputSource::from(&buffer); + + // Act + let result = source.does_buffer_have_at_least(5); + + // Assert + assert!(result.is_ok()); + } + + /// Verifies that [`does_buffer_have_at_least`] returns an error when the remaining bytes number are less than + /// the number of requested bytes. + #[test] + fn does_buffer_have_at_least_returns_error() { + // Arrange + let source = SliceInputSource::from(&[115, 108, 105, 99, 101]); + + // Act + let result = source.does_buffer_have_at_least(6); + + // Assert + assert!(result.is_err()); + assert!(matches!(result.unwrap_err().kind(), ErrorKind::UnexpectedEob { + requested: 6, + remaining: 5 + })); + } + + /// Verifies that [`peek_byte`] returns the correct byte from the buffer without consuming it. + #[test] + fn peek_byte_returns_correct_byte() { + // Arrange + let mut source = SliceInputSource::from(&[115, 108, 105, 99, 101]); + + // Act + let result = source.peek_byte(); + + // Assert + assert!(result.is_ok()); + assert_eq!(result.unwrap(), 115); + assert_eq!(source.pos, 0); + assert_eq!(source.remaining(), 5); + } + + /// Verifies that [`read_byte`] returns the correct byte from the buffer and consumes it. + #[test] + fn read_byte_returns_correct_byte() { + // Arrange + let mut source = SliceInputSource::from(&[115, 108, 105, 99, 101]); + + // Act + let result = source.read_byte(); + + // Assert + assert!(result.is_ok()); + assert_eq!(result.unwrap(), 115); + assert_eq!(source.pos, 1); + assert_eq!(source.remaining(), 4); + } + + /// Verifies that [`read_bytes_exact`] returns the correct number of bytes from the buffer and consumes them. + #[test] + fn read_bytes_exact_returns_correct_bytes() { + // Arrange + let mut source = SliceInputSource::from(&[115, 108, 105, 99, 101]); + + // Act + let result = source.read_bytes_exact::<3>(); + + // Assert + assert!(result.is_ok()); + assert_eq!(result.unwrap(), &[115, 108, 105]); + assert_eq!(source.pos, 3); + assert_eq!(source.remaining(), 2); + } +} diff --git a/slice-codec/src/lib.rs b/slice-codec/src/lib.rs index 8876d67f..f5a213d9 100644 --- a/slice-codec/src/lib.rs +++ b/slice-codec/src/lib.rs @@ -14,18 +14,16 @@ extern crate alloc; #[cfg(feature = "std")] extern crate std; -// These modules are private because they don't export any types, just implementations. +pub mod input_source; +pub mod output_target; + mod decoding; mod encoding; - -pub mod buffer; -pub mod decode_from; -pub mod decoder; -pub mod encode_into; -pub mod encoder; - -// Re-export the contents of the `error` module directly into the crate root, so they're easier to reference. mod error; + +// Re-export the contents of some modules directly into the crate root, so they're easier to reference. +pub use decoding::*; +pub use encoding::*; pub use error::*; /// The smallest value that can be represented as a `varint32`. diff --git a/slice-codec/src/buffer/mod.rs b/slice-codec/src/output_target/mod.rs similarity index 68% rename from slice-codec/src/buffer/mod.rs rename to slice-codec/src/output_target/mod.rs index 578b8967..9e197806 100644 --- a/slice-codec/src/buffer/mod.rs +++ b/slice-codec/src/output_target/mod.rs @@ -2,45 +2,17 @@ //! TODO maybe write a comment explaining this module? -pub mod slice; +mod slice_output_target; +pub use slice_output_target::*; #[cfg(feature = "alloc")] -pub mod vec; +mod vec_output_target; +#[cfg(feature = "alloc")] +pub use vec_output_target::*; use crate::Result; use core::ops::Range; -/// A trait for types that can be read from by a [Slice decoder](crate::decoder::Decoder). -pub trait InputSource { - /// Returns the number of unread bytes currently remaining in the source. - fn remaining(&self) -> usize; - - /// Returns the next byte available from this source without consuming it. - /// - /// If there are no more bytes available from this source, an [`UnexpectedEob`] error is returned instead. - /// - /// [`UnexpectedEob`]: crate::ErrorKind::UnexpectedEob - fn peek_byte(&mut self) -> Result; - - /// Returns the next byte available from this source, and advances past it (consuming it). - /// - /// If there are no more bytes available from this source, an [`UnexpectedEob`] error is returned instead. - /// - /// [`UnexpectedEob`]: crate::ErrorKind::UnexpectedEob - fn read_byte(&mut self) -> Result; - - // TODO remove these functions after adding `advance_by` and the low-level required API functions. - fn read_bytes_exact(&mut self) -> Result<&[u8; N]>; - fn read_byte_slice_exact(&mut self, count: usize) -> Result<&[u8]>; - - /// Reads bytes from this source into the provided buffer, and advances past them (consuming them). - /// - /// This function reads exactly `dest.len()`-many bytes, or if it's unable to, returns an error instead. - /// If such an error occurs, no guarantees are made about how many bytes were read from the source, except that it - /// is less than `dest.len()`. - fn read_bytes_into_exact(&mut self, dest: &mut [u8]) -> Result<()>; -} - /// A trait for types that can be written to by a [Slice encoder](crate::encoder::Encoder). pub trait OutputTarget { /// Returns the number of unwritten bytes currently remaining in the target. diff --git a/slice-codec/src/output_target/slice_output_target.rs b/slice-codec/src/output_target/slice_output_target.rs new file mode 100644 index 00000000..6960beb4 --- /dev/null +++ b/slice-codec/src/output_target/slice_output_target.rs @@ -0,0 +1,254 @@ +// Copyright (c) ZeroC, Inc. + +//! TODO maybe write a comment explaining this module? + +use super::*; +use crate::{ErrorKind, Result}; +use core::{debug_assert, debug_assert_eq}; + +/// A wrapper around a `&mut [u8]` that implements [`OutputTarget`]. +#[derive(Debug)] +pub struct SliceOutputTarget<'a> { + /// The underlying buffer that this type wraps. + buffer: &'a mut [u8], + /// Tracks the current position in the buffer that is being written to. + pos: usize, +} + +impl<'a> SliceOutputTarget<'a> { + /// Checks whether there are at least `requested` unwritten bytes left in the buffer. + /// If there are, this returns `Ok`, and if there aren't this returns an [`ErrorKind::UnexpectedEob`] error. + /// + /// This function is only used internally to ensure a particular write operation is safe to attempt. + fn does_buffer_have_at_least(&self, requested: usize) -> Result<()> { + let remaining = self.remaining(); + if remaining < requested { + let error = ErrorKind::UnexpectedEob { requested, remaining }; + Err(error.into()) + } else { + Ok(()) + } + } +} + +impl OutputTarget for SliceOutputTarget<'_> { + fn remaining(&self) -> usize { + self.buffer.len() - self.pos + } + + fn write_byte(&mut self, byte: u8) -> Result<()> { + self.does_buffer_have_at_least(1)?; + + // SAFETY: the above function call guarantees there's enough space in `self.buffer` to write a single byte. + unsafe { + debug_assert!(self.buffer.get_mut(self.pos).is_some()); + *self.buffer.get_unchecked_mut(self.pos) = byte; + self.pos += 1; + Ok(()) + } + } + + fn write_bytes_exact(&mut self, bytes: &[u8]) -> Result<()> { + let count = bytes.len(); + self.does_buffer_have_at_least(count)?; + + // SAFETY: the above function call guarantees there's enough space in `self.buffer` to write `bytes`, + // and we know the slices cannot overlap because the mutable borrow of `self` guarantees exclusive access. + unsafe { + let end = self.pos + count; + debug_assert!(self.buffer.get_mut(self.pos..end).is_some()); + let target_slice = self.buffer.get_unchecked_mut(self.pos..end); + debug_assert_eq!(target_slice.len(), count); + + core::ptr::copy_nonoverlapping(bytes.as_ptr(), target_slice.as_mut_ptr(), count); + self.pos = end; + Ok(()) + } + } + + fn write_bytes_into_reserved_exact(&mut self, reservation: &mut Reservation, bytes: &[u8]) -> Result<()> { + // Get a mutable slice of the buffer - one that corresponds to the reserved range. + let Some(reserved_slice) = self.buffer.get_mut(reservation.range()) else { + let error = ErrorKind::InvalidReservation { + buffer_len: self.buffer.len(), + reserved_range: reservation.range(), + }; + return Err(error.into()); + }; + + // Ensure there's enough space remaining in the reservation. + if reserved_slice.len() < bytes.len() { + let error = ErrorKind::UnexpectedEob { + requested: bytes.len(), + remaining: reserved_slice.len(), + }; + return Err(error.into()); + } + + // SAFETY: we just checked that there's enough space in `reserved_slice` to write `bytes`, + // and we know the slices cannot overlap because the mutable borrow of `self` guarantees exclusive access. + unsafe { + core::ptr::copy_nonoverlapping(bytes.as_ptr(), reserved_slice.as_mut_ptr(), bytes.len()); + reservation.0.start += bytes.len(); + Ok(()) + } + } + + fn reserve_space(&mut self, count: usize) -> Result { + self.does_buffer_have_at_least(count)?; + + self.pos += count; + Ok(Reservation((self.pos - count)..self.pos)) + } +} + +impl<'a> From<&'a mut [u8]> for SliceOutputTarget<'a> { + /// Creates a new [`SliceOutputTarget`] that wraps the provided buffer. + fn from(value: &'a mut [u8]) -> Self { + Self { buffer: value, pos: 0 } + } +} + +impl<'a, const N: usize> From<&'a mut [u8; N]> for SliceOutputTarget<'a> { + /// Creates a new [`SliceOutputTarget`] that wraps the provided array. + fn from(value: &'a mut [u8; N]) -> Self { + Self { + buffer: value.as_mut_slice(), + pos: 0, + } + } +} + +// Allows users to create an [`Encoder`] directly from a slice, +// without needing to construct an intermediate [`SliceOutputTarget`]. +impl<'a, T> From for crate::encoding::encoder::Encoder> +where + T: Into>, +{ + fn from(value: T) -> Self { + crate::encoding::encoder::Encoder::new(value.into()) + } +} + +#[cfg(test)] +mod tests { + + use super::*; + + /// Verifies that [`does_buffer_have_at_least`] returns the correct number of remaining bytes in the buffer + /// when the remaining bytes number are greater than or equal to the number of requested bytes. + #[test] + fn does_buffer_has_at_least_returns_ok() { + // Arrange + let mut buffer = [115, 108, 105, 99, 101]; + let target = SliceOutputTarget::from(buffer.as_mut_slice()); + + // Act + let result = target.does_buffer_have_at_least(5); + + // Assert + assert!(result.is_ok()); + } + + /// Verifies that [`does_buffer_have_at_least`] returns an error when the remaining bytes number are less than + /// the number of requested bytes. + #[test] + fn does_buffer_have_at_least_returns_error() { + // Arrange + let mut buffer = [115, 108, 105, 99, 101]; + let target = SliceOutputTarget::from(buffer.as_mut_slice()); + + // Act + let result = target.does_buffer_have_at_least(6); + + // Assert + assert!(result.is_err()); + assert!(matches!(result.unwrap_err().kind(), ErrorKind::UnexpectedEob { + requested: 6, + remaining: 5 + })); + } + + /// Verifies that [`write_byte`] writes the correct byte to the buffer and advances the position. + #[test] + fn write_byte_writes_correct_byte() { + // Arrange + let mut buffer = [0; 5]; + let mut target = SliceOutputTarget::from(buffer.as_mut_slice()); + + // Act + let result = target.write_byte(115); + + // Assert + assert!(result.is_ok()); + assert_eq!(target.buffer, [115, 0, 0, 0, 0]); + assert_eq!(target.pos, 1); + assert_eq!(target.remaining(), 4); + } + + /// Verifies that [`write_bytes_exact`] writes the correct bytes to the buffer and advances the position. + #[test] + fn write_bytes_exact_writes_correct_bytes() { + // Arrange + let mut buffer = [0; 5]; + let mut target = SliceOutputTarget::from(buffer.as_mut_slice()); + + // Act + let result = target.write_bytes_exact(&[115, 108, 105, 99, 101]); + + // Assert + assert!(result.is_ok()); + assert_eq!(target.buffer, [115, 108, 105, 99, 101]); + assert_eq!(target.pos, 5); + assert_eq!(target.remaining(), 0); + } + + /// Verifies that [`reserve_space`] reserves the correct number of bytes in the buffer and advances the + /// position past the reserved space so that the next write operation will not write into the reserved space. + #[test] + fn reserve_space_reserves_correct_space() { + // Arrange + let mut buffer = [0; 5]; + let mut target = SliceOutputTarget::from(buffer.as_mut_slice()); + + // Act + let reserve_result = target.reserve_space(3); + let write_result = target.write_byte(99); + + // Assert + assert!(reserve_result.is_ok()); + assert!(write_result.is_ok()); + + assert_eq!(reserve_result.unwrap().0, 0..3); + assert_eq!(target.pos, 4); + assert_eq!(target.remaining(), 1); + assert_eq!(target.buffer, [0, 0, 0, 99, 0]); + } + + /// Verifies that [`write_bytes_into_reserved_exact`] writes the correct bytes to the reserved space in the + /// buffer and does not advance the position past the reserved space. + #[test] + fn write_bytes_into_reserved_exact_writes_correct_bytes() { + // Arrange + let mut buffer = [0; 5]; + let mut target = SliceOutputTarget::from(buffer.as_mut_slice()); + + // Should advance the position to 3. + let mut reservation = target.reserve_space(3).unwrap(); + + // Write a byte to ensure the position is advanced. + let _ = target.write_bytes_exact(&[99]); + + // Act + let result = target.write_bytes_into_reserved_exact(&mut reservation, &[115, 108, 105]); + + // Write a byte to ensure the position was not advanced. + let _ = target.write_byte(101); + + // Assert + assert!(result.is_ok()); + assert_eq!(target.buffer, [115, 108, 105, 99, 101]); + assert_eq!(target.pos, 5); + assert_eq!(target.remaining(), 0); + } +} diff --git a/slice-codec/src/buffer/vec.rs b/slice-codec/src/output_target/vec_output_target.rs similarity index 90% rename from slice-codec/src/buffer/vec.rs rename to slice-codec/src/output_target/vec_output_target.rs index 442796a8..d50ec312 100644 --- a/slice-codec/src/buffer/vec.rs +++ b/slice-codec/src/output_target/vec_output_target.rs @@ -46,12 +46,15 @@ impl OutputTarget for VecOutputTarget<'_> { fn write_byte(&mut self, byte: u8) -> Result<()> { self.ensure_buffer_has_at_least(1)?; - // SAFETY: the above function call guarantees there's enough space in `self.buffer` to write a single byte. + // SAFETY: the above function call guarantees there's enough spare capacity in `self.buffer` to write 1 byte, + // and we only write into the vector's spare capacity, we never read from it (it's uninitialized at this point). unsafe { + // Write the byte into the buffer's spare capacity. debug_assert!(self.buffer.spare_capacity_mut().get_mut(0).is_some()); let target = self.buffer.spare_capacity_mut().get_unchecked_mut(0); target.write(byte); + // Increase the buffer's length by 1, since we just wrote a byte into it. let old_length = self.buffer.len(); self.buffer.set_len(old_length + 1); Ok(()) @@ -63,17 +66,18 @@ impl OutputTarget for VecOutputTarget<'_> { self.ensure_buffer_has_at_least(count)?; // SAFETY: the above function call guarantees there's enough spare capacity in `self.buffer` to write `bytes`, - // and we know the slice cannot overlap because the mutable borrow of `self` guarantees exclusive access. + // and we know the slices cannot overlap because the mutable borrow of `self` guarantees exclusive access, + // and we only write into the vector's spare capacity, we never read from it (it's uninitialized at this point). unsafe { debug_assert!(self.buffer.spare_capacity_mut().get_mut(..count).is_some()); let target_slice = self.buffer.spare_capacity_mut().get_unchecked_mut(..count); - debug_assert_eq!(target_slice.len(), count); // SAFETY: `MaybeUninit` is guaranteed to have the same memory layout as `T`. - let source: &[MaybeUninit] = core::mem::transmute(bytes); - - core::ptr::copy_nonoverlapping(source.as_ptr(), target_slice.as_mut_ptr(), count); + debug_assert_eq!(target_slice.len(), count); + let source_slice: &[MaybeUninit] = core::mem::transmute(bytes); + core::ptr::copy_nonoverlapping(source_slice.as_ptr(), target_slice.as_mut_ptr(), count); + // Increase the buffer's length by 'count', since we just wrote that many bytes into it. let old_length = self.buffer.len(); self.buffer.set_len(old_length + count); Ok(()) @@ -138,12 +142,12 @@ impl<'a> From<&'a mut Vec> for VecOutputTarget<'a> { // Allows users to create an [`Encoder`] directly from a vector, // without needing to construct an intermediate [`VecOutputTarget`]. -impl<'a, T> From for crate::encoder::Encoder> +impl<'a, T> From for crate::encoding::encoder::Encoder> where T: Into>, { fn from(value: T) -> Self { - crate::encoder::Encoder::new(value.into()) + crate::encoding::encoder::Encoder::new(value.into()) } } diff --git a/slice-codec/tests/encoding_tests.rs b/slice-codec/tests/encoding_tests.rs index 2f076054..4101927a 100644 --- a/slice-codec/tests/encoding_tests.rs +++ b/slice-codec/tests/encoding_tests.rs @@ -5,8 +5,8 @@ #[cfg(test)] mod fixed_size { - use slice_codec::buffer::slice::{SliceInputSource, SliceOutputTarget}; - use slice_codec::buffer::{InputSource, OutputTarget}; + use slice_codec::input_source::{InputSource, SliceInputSource}; + use slice_codec::output_target::{OutputTarget, SliceOutputTarget}; use slice_codec::decode_from::DecodeFrom; use slice_codec::decoder::Decoder; use slice_codec::encode_into::EncodeInto; @@ -141,7 +141,8 @@ mod fixed_size { #[cfg(test)] mod variable_sized { - use slice_codec::buffer::slice::{SliceInputSource, SliceOutputTarget}; + use slice_codec::input_source::SliceInputSource; + use slice_codec::output_target::SliceOutputTarget; use slice_codec::decoder::Decoder; use slice_codec::encoder::Encoder; @@ -264,7 +265,7 @@ mod variable_sized { fn string(str: &str) { // Arrange let mut buffer = vec![]; - let output_target = slice_codec::buffer::vec::VecOutputTarget::from(&mut buffer); + let output_target = slice_codec::output_target::VecOutputTarget::from(&mut buffer); let mut encoder = Encoder::new(output_target); let utf8_byte_count = str.len(); // Strings are always UTF-8, and `len` returns the number of bytes. @@ -355,7 +356,7 @@ mod variable_sized { fn string(str: &str) { // Arrange let mut buffer = vec![]; - let output_target = slice_codec::buffer::vec::VecOutputTarget::from(&mut buffer); + let output_target = slice_codec::output_target::VecOutputTarget::from(&mut buffer); let mut encoder = Encoder::new(output_target); encoder.encode(str).expect("failed to encode string"); @@ -393,7 +394,7 @@ mod variable_sized { #[test] #[cfg(feature = "std")] fn dictionary_decoding_rejects_duplicate_key() { - use slice_codec::buffer::vec::VecOutputTarget; + use slice_codec::output_target::VecOutputTarget; use std::collections::HashMap; // Arrange diff --git a/slicec/src/definition_types.rs b/slicec/src/definition_types.rs index 31a1d5f5..ac579f05 100644 --- a/slicec/src/definition_types.rs +++ b/slicec/src/definition_types.rs @@ -5,7 +5,8 @@ #![allow(dead_code)] -use slice_codec::buffer::{InputSource, OutputTarget}; +use slice_codec::input_source::InputSource; +use slice_codec::output_target::OutputTarget; use slice_codec::decode_from::DecodeFrom; use slice_codec::decoder::Decoder; use slice_codec::encode_into::EncodeInto; From 6e259ed5c01f2b092e32ab5e8d9dd6e539492085 Mon Sep 17 00:00:00 2001 From: Austin Henriksen Date: Thu, 30 Jul 2026 15:28:36 -0400 Subject: [PATCH 2/3] Formatting fixes. --- .../src/decoding/{decoding.rs => implementations.rs} | 0 slice-codec/src/decoding/mod.rs | 2 +- .../src/encoding/{encoding.rs => implementations.rs} | 0 slice-codec/src/encoding/mod.rs | 2 +- slice-codec/tests/encoding_tests.rs | 8 ++++---- slicec/src/definition_types.rs | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) rename slice-codec/src/decoding/{decoding.rs => implementations.rs} (100%) rename slice-codec/src/encoding/{encoding.rs => implementations.rs} (100%) diff --git a/slice-codec/src/decoding/decoding.rs b/slice-codec/src/decoding/implementations.rs similarity index 100% rename from slice-codec/src/decoding/decoding.rs rename to slice-codec/src/decoding/implementations.rs diff --git a/slice-codec/src/decoding/mod.rs b/slice-codec/src/decoding/mod.rs index 43e3edc7..a0269dbc 100644 --- a/slice-codec/src/decoding/mod.rs +++ b/slice-codec/src/decoding/mod.rs @@ -4,4 +4,4 @@ pub mod decode_from; pub mod decoder; // This module is private because it doesn't export any types, just implementations. -mod decoding; +mod implementations; diff --git a/slice-codec/src/encoding/encoding.rs b/slice-codec/src/encoding/implementations.rs similarity index 100% rename from slice-codec/src/encoding/encoding.rs rename to slice-codec/src/encoding/implementations.rs diff --git a/slice-codec/src/encoding/mod.rs b/slice-codec/src/encoding/mod.rs index f6d98871..98be473c 100644 --- a/slice-codec/src/encoding/mod.rs +++ b/slice-codec/src/encoding/mod.rs @@ -4,4 +4,4 @@ pub mod encode_into; pub mod encoder; // This module is private because it doesn't export any types, just implementations. -mod encoding; +mod implementations; diff --git a/slice-codec/tests/encoding_tests.rs b/slice-codec/tests/encoding_tests.rs index 4101927a..d4f76035 100644 --- a/slice-codec/tests/encoding_tests.rs +++ b/slice-codec/tests/encoding_tests.rs @@ -5,12 +5,12 @@ #[cfg(test)] mod fixed_size { - use slice_codec::input_source::{InputSource, SliceInputSource}; - use slice_codec::output_target::{OutputTarget, SliceOutputTarget}; use slice_codec::decode_from::DecodeFrom; use slice_codec::decoder::Decoder; use slice_codec::encode_into::EncodeInto; use slice_codec::encoder::Encoder; + use slice_codec::input_source::{InputSource, SliceInputSource}; + use slice_codec::output_target::{OutputTarget, SliceOutputTarget}; use test_case::test_case; @@ -141,10 +141,10 @@ mod fixed_size { #[cfg(test)] mod variable_sized { - use slice_codec::input_source::SliceInputSource; - use slice_codec::output_target::SliceOutputTarget; use slice_codec::decoder::Decoder; use slice_codec::encoder::Encoder; + use slice_codec::input_source::SliceInputSource; + use slice_codec::output_target::SliceOutputTarget; #[cfg(feature = "alloc")] use slice_codec::{ErrorKind, InvalidDataErrorKind}; diff --git a/slicec/src/definition_types.rs b/slicec/src/definition_types.rs index ac579f05..06a84ebf 100644 --- a/slicec/src/definition_types.rs +++ b/slicec/src/definition_types.rs @@ -5,12 +5,12 @@ #![allow(dead_code)] -use slice_codec::input_source::InputSource; -use slice_codec::output_target::OutputTarget; use slice_codec::decode_from::DecodeFrom; use slice_codec::decoder::Decoder; use slice_codec::encode_into::EncodeInto; use slice_codec::encoder::Encoder; +use slice_codec::input_source::InputSource; +use slice_codec::output_target::OutputTarget; use slice_codec::Result; /// TAG_END_MARKER must be encoded at the end of every non-compact type. From 1ce06926a050b34ef80b0eeee377d558c91e348b Mon Sep 17 00:00:00 2001 From: Austin Henriksen Date: Thu, 30 Jul 2026 15:33:36 -0400 Subject: [PATCH 3/3] Fixed broken doc-link. --- slice-codec/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slice-codec/src/error.rs b/slice-codec/src/error.rs index 0f6fbb78..cc736ec5 100644 --- a/slice-codec/src/error.rs +++ b/slice-codec/src/error.rs @@ -105,7 +105,7 @@ pub enum ErrorKind { /// A buffer reservation did not fit within its buffer. /// This error represents a serious problem in the implementation, or intentional tampering by callers. - /// See [`write_bytes_exact_into_reserved`](crate::buffer::OutputTarget::write_bytes_into_reserved_exact). + /// See [`write_bytes_exact_into_reserved`](crate::output_target::OutputTarget::write_bytes_into_reserved_exact). InvalidReservation { /// The length of the buffer. buffer_len: usize,