Add new prefixed encoders for BytesEncoder and SliceEncoder
What changed, and why it matters
This commit adds two new helper types, PrefixedBytesEncoder and PrefixedSliceEncoder, to make it easier to encode byte slices and lists of items with a length prefix. It is a straightforward feature/refactoring change with no security relevance visible in the code or commit message.
No security action needed. Review as normal code-quality/feature change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch introduces PrefixedBytesEncoder and PrefixedSliceEncoder in consensus_encoding/src/encode/encoders.rs and re-exports them in consensus_encoding/src/lib.rs. Both are thin wrappers around the existing Encoder2
Changed components
consensus_encoding/src/encode/encoders.rsconsensus_encoding/src/lib.rsInspect captured patch +69 / −4
diff --git a/consensus_encoding/src/encode/encoders.rs b/consensus_encoding/src/encode/encoders.rs
index c5b9a615..23639ccb 100644
--- a/consensus_encoding/src/encode/encoders.rs
+++ b/consensus_encoding/src/encode/encoders.rs
@@ -13,6 +13,7 @@
use core::fmt;
use super::{Encode, Encoder, EncoderStatus, ExactSizeEncoder};
+use crate::CompactSizeEncoder;
/// An encoder for a single byte slice.
#[derive(Debug, Clone)]
@@ -36,6 +37,34 @@ impl<'sl> ExactSizeEncoder for BytesEncoder<'sl> {
fn len(&self) -> usize { self.sl.len() }
}
+/// An encoder for a single byte slice, including a compact size length prefix.
+#[derive(Debug, Clone)]
+pub struct PrefixedBytesEncoder<'sl>(Encoder2<CompactSizeEncoder, BytesEncoder<'sl>>);
+
+impl<'sl> PrefixedBytesEncoder<'sl> {
+ /// Constructs a byte encoder which encodes the given byte slice, with a length prefix.
+ #[inline]
+ pub fn new(sl: &'sl [u8]) -> Self {
+ Self(Encoder2::new(
+ CompactSizeEncoder::new(sl.len()),
+ BytesEncoder::without_length_prefix(sl),
+ ))
+ }
+}
+
+impl Encoder for PrefixedBytesEncoder<'_> {
+ #[inline]
+ fn current_chunk(&self) -> &[u8] { self.0.current_chunk() }
+
+ #[inline]
+ fn advance(&mut self) -> EncoderStatus { self.0.advance() }
+}
+
+impl ExactSizeEncoder for PrefixedBytesEncoder<'_> {
+ #[inline]
+ fn len(&self) -> usize { self.0.len() }
+}
+
/// An encoder for a single array.
#[derive(Debug, Clone)]
pub struct ArrayEncoder<const N: usize> {
@@ -98,9 +127,7 @@ pub struct SliceEncoder<'e, T: Encode> {
impl<'e, T: Encode> SliceEncoder<'e, T> {
/// Constructs an encoder which encodes the slice _without_ adding the length prefix.
///
- /// To encode with a length prefix consider using [`Encoder2`].
- ///
- /// E.g, `Encoder2<CompactSizeEncoder, SliceEncoder<'e, Foo>>`.
+ /// To encode with a length prefix, use [`PrefixedSliceEncoder`] instead.
pub fn without_length_prefix(sl: &'e [T]) -> Self {
// In this `map` call we cannot remove the closure. Seems to be a bug in the compiler.
// Perhaps https://github.com/rust-lang/rust/issues/102540 which is 3 years old with
@@ -164,6 +191,44 @@ impl<T: Encode> Encoder for SliceEncoder<'_, T> {
}
}
+/// An encoder for a list of encodable types, including a length prefix.
+pub struct PrefixedSliceEncoder<'e, T: Encode>(Encoder2<CompactSizeEncoder, SliceEncoder<'e, T>>);
+
+impl<'e, T: Encode> PrefixedSliceEncoder<'e, T> {
+ /// Constructs an encoder which encodes the slice, adding the length prefix.
+ #[inline]
+ pub fn new(sl: &'e [T]) -> Self {
+ Self(Encoder2::new(
+ CompactSizeEncoder::new(sl.len()),
+ SliceEncoder::without_length_prefix(sl),
+ ))
+ }
+}
+
+impl<'e, T: Encode> fmt::Debug for PrefixedSliceEncoder<'e, T>
+where
+ T::Encoder<'e>: fmt::Debug,
+{
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) }
+}
+
+impl<'e, T: Encode> Clone for PrefixedSliceEncoder<'e, T>
+where
+ T::Encoder<'e>: Clone,
+{
+ #[inline]
+ fn clone(&self) -> Self { Self(self.0.clone()) }
+}
+
+impl<T: Encode> Encoder for PrefixedSliceEncoder<'_, T> {
+ #[inline]
+ fn current_chunk(&self) -> &[u8] { self.0.current_chunk() }
+
+ #[inline]
+ fn advance(&mut self) -> EncoderStatus { self.0.advance() }
+}
+
/// Helper macro to define an unrolled `EncoderN` composite encoder.
macro_rules! define_encoder_n {
(
diff --git a/consensus_encoding/src/lib.rs b/consensus_encoding/src/lib.rs
index 7160e7d1..4ecd7e95 100644
--- a/consensus_encoding/src/lib.rs
+++ b/consensus_encoding/src/lib.rs
@@ -116,7 +116,7 @@ pub use self::decode::{
#[doc(inline)]
pub use self::encode::encoders::{
ArrayEncoder, ArrayRefEncoder, BytesEncoder, Encoder2, Encoder3, Encoder4, Encoder6,
- SliceEncoder,
+ PrefixedBytesEncoder, PrefixedSliceEncoder, SliceEncoder,
};
#[doc(inline)]
pub use self::encode::{
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.