Remove option from current_chunk function signature
What changed, and why it matters
This commit is a routine internal code cleanup in the rust-bitcoin library. It changes an encoding helper function so that it returns an empty byte slice instead of a special 'no value' (None) marker when there is nothing left to encode. The behavior of the code is intended to stay the same; only the way callers check for the end of data is simplified. There is no indication this fixes a security bug.
No security action required. Treat as normal refactoring; review for API compatibility if downstream code depends on the previous `Option<&[u8]>` return type.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit refactors the Encoder::current_chunk trait method from returning Option<&[u8]> to returning &[u8], using an empty slice (&[]) as the exhausted state instead of None. Implementations and call sites in consensus_encoding and primitives are updated to use .is_empty() rather than .is_some(). The diff is dominated by test assertion rewrites. No cryptographic, consensus, or serialization logic is changed; this is an API ergonomics refactor.
Changed components
consensus_encoding/src/encode/encoders.rsconsensus_encoding/src/encode/mod.rsconsensus_encoding/tests/composition.rsconsensus_encoding/tests/encode.rsprimitives/src/transaction.rsprimitives/src/witness.rsInspect captured patch +227 / −225
diff --git a/consensus_encoding/src/encode/encoders.rs b/consensus_encoding/src/encode/encoders.rs
index 4b617edf..691bffb1 100644
--- a/consensus_encoding/src/encode/encoders.rs
+++ b/consensus_encoding/src/encode/encoders.rs
@@ -30,7 +30,9 @@ impl<'sl> BytesEncoder<'sl> {
}
impl Encoder for BytesEncoder<'_> {
- fn current_chunk(&self) -> Option<&[u8]> { self.sl }
+ fn current_chunk(&self) -> &[u8] {
+ self.sl.unwrap_or_default()
+ }
fn advance(&mut self) -> bool {
self.sl = None;
@@ -50,7 +52,7 @@ impl<const N: usize> ArrayEncoder<N> {
impl<const N: usize> Encoder for ArrayEncoder<N> {
#[inline]
- fn current_chunk(&self) -> Option<&[u8]> { self.arr.as_ref().map(|x| &x[..]) }
+ fn current_chunk(&self) -> &[u8] { self.arr.as_ref().map(|x| &x[..]).unwrap_or_default() }
#[inline]
fn advance(&mut self) -> bool {
@@ -82,10 +84,9 @@ impl<'e, T: Encodable> SliceEncoder<'e, T> {
}
impl<T: Encodable> Encoder for SliceEncoder<'_, T> {
- fn current_chunk(&self) -> Option<&[u8]> {
+ fn current_chunk(&self) -> &[u8] {
// `advance` sets `cur_enc` to `None` once the slice encoder is completely exhausted.
- // `current_chunk` is required to return `None` if called after the encoder is exhausted.
- self.cur_enc.as_ref().and_then(T::Encoder::current_chunk)
+ self.cur_enc.as_ref().map(T::Encoder::current_chunk).unwrap_or_default()
}
fn advance(&mut self) -> bool {
@@ -105,7 +106,7 @@ impl<T: Encodable> Encoder for SliceEncoder<'_, T> {
// If advancing the current encoder failed, attempt to move to the next encoder.
if let Some(x) = self.sl.first() {
*cur = x.encoder();
- if cur.current_chunk().is_some() {
+ if !cur.current_chunk().is_empty() {
return true;
}
} else {
@@ -130,7 +131,7 @@ impl<A, B> Encoder2<A, B> {
impl<A: Encoder, B: Encoder> Encoder for Encoder2<A, B> {
#[inline]
- fn current_chunk(&self) -> Option<&[u8]> {
+ fn current_chunk(&self) -> &[u8] {
if self.enc_idx == 0 {
self.enc_1.current_chunk()
} else {
@@ -170,7 +171,7 @@ impl<A, B, C> Encoder3<A, B, C> {
impl<A: Encoder, B: Encoder, C: Encoder> Encoder for Encoder3<A, B, C> {
#[inline]
- fn current_chunk(&self) -> Option<&[u8]> { self.inner.current_chunk() }
+ fn current_chunk(&self) -> &[u8] { self.inner.current_chunk() }
#[inline]
fn advance(&mut self) -> bool { self.inner.advance() }
}
@@ -189,7 +190,7 @@ impl<A, B, C, D> Encoder4<A, B, C, D> {
impl<A: Encoder, B: Encoder, C: Encoder, D: Encoder> Encoder for Encoder4<A, B, C, D> {
#[inline]
- fn current_chunk(&self) -> Option<&[u8]> { self.inner.current_chunk() }
+ fn current_chunk(&self) -> &[u8] { self.inner.current_chunk() }
#[inline]
fn advance(&mut self) -> bool { self.inner.advance() }
}
@@ -215,7 +216,7 @@ impl<A: Encoder, B: Encoder, C: Encoder, D: Encoder, E: Encoder, F: Encoder> Enc
for Encoder6<A, B, C, D, E, F>
{
#[inline]
- fn current_chunk(&self) -> Option<&[u8]> { self.inner.current_chunk() }
+ fn current_chunk(&self) -> &[u8] { self.inner.current_chunk() }
#[inline]
fn advance(&mut self) -> bool { self.inner.advance() }
}
@@ -232,7 +233,7 @@ impl CompactSizeEncoder {
impl Encoder for CompactSizeEncoder {
#[inline]
- fn current_chunk(&self) -> Option<&[u8]> { self.buf.as_ref().map(|b| &b[..]) }
+ fn current_chunk(&self) -> &[u8] { self.buf.as_ref().map(|b| &b[..]).unwrap_or_default() }
#[inline]
fn advance(&mut self) -> bool {
@@ -272,9 +273,9 @@ mod tests {
// Should have one chunk with the array data, then exhausted.
let test_array = TestArray([1u8, 2, 3, 4]);
let mut encoder = test_array.encoder();
- assert_eq!(encoder.current_chunk(), Some(&[1u8, 2, 3, 4][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8, 2, 3, 4][..]);
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -282,9 +283,9 @@ mod tests {
// Empty array should have one empty chunk, then exhausted.
let test_array = TestArray([]);
let mut encoder = test_array.encoder();
- assert_eq!(encoder.current_chunk(), Some(&[][..]));
+ assert!(encoder.current_chunk().is_empty());
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -294,9 +295,9 @@ mod tests {
let test_bytes = TestBytes(&obj);
let mut encoder = test_bytes.encoder();
- assert_eq!(encoder.current_chunk(), Some(&[1u8, 2, 3][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8, 2, 3][..]);
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -306,9 +307,9 @@ mod tests {
let test_bytes = TestBytes(&obj);
let mut encoder = test_bytes.encoder();
- assert_eq!(encoder.current_chunk(), Some(&[][..]));
+ assert!(encoder.current_chunk().is_empty());
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -317,11 +318,11 @@ mod tests {
let slice = &[TestArray([0x34, 0x12, 0x00, 0x00]), TestArray([0x78, 0x56, 0x00, 0x00])];
let mut encoder = SliceEncoder::without_length_prefix(slice);
- assert_eq!(encoder.current_chunk(), Some(&[0x34, 0x12, 0x00, 0x00][..]));
+ assert_eq!(encoder.current_chunk(), &[0x34, 0x12, 0x00, 0x00][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x78, 0x56, 0x00, 0x00][..]));
+ assert_eq!(encoder.current_chunk(), &[0x78, 0x56, 0x00, 0x00][..]);
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -331,7 +332,7 @@ mod tests {
let mut encoder = SliceEncoder::without_length_prefix(slice);
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -340,11 +341,12 @@ mod tests {
let slice = &[TestArray([]), TestArray([])];
let mut encoder = SliceEncoder::without_length_prefix(slice);
- assert_eq!(encoder.current_chunk(), Some(&[][..]));
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[][..]));
+ assert!(encoder.current_chunk().is_empty());
+ // FIXME: Its strange the we can't do this?
+ // assert!(encoder.advance());
+ // assert!(encoder.current_chunk().is_empty());
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -354,11 +356,11 @@ mod tests {
let enc2 = TestArray([3u8, 4]).encoder();
let mut encoder = Encoder2::new(enc1, enc2);
- assert_eq!(encoder.current_chunk(), Some(&[1u8, 2][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8, 2][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[3u8, 4][..]));
+ assert_eq!(encoder.current_chunk(), &[3u8, 4][..]);
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -368,11 +370,11 @@ mod tests {
let enc2 = TestArray([]).encoder();
let mut encoder = Encoder2::new(enc1, enc2);
- assert_eq!(encoder.current_chunk(), Some(&[][..]));
+ assert!(encoder.current_chunk().is_empty());
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[][..]));
+ assert!(encoder.current_chunk().is_empty());
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -383,13 +385,13 @@ mod tests {
let enc3 = TestArray([4u8, 5u8, 6u8]).encoder();
let mut encoder = Encoder3::new(enc1, enc2, enc3);
- assert_eq!(encoder.current_chunk(), Some(&[1u8][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[2u8, 3u8][..]));
+ assert_eq!(encoder.current_chunk(), &[2u8, 3u8][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[4u8, 5u8, 6u8][..]));
+ assert_eq!(encoder.current_chunk(), &[4u8, 5u8, 6u8][..]);
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -401,15 +403,15 @@ mod tests {
let enc4 = TestArray([0x40]).encoder();
let mut encoder = Encoder4::new(enc1, enc2, enc3, enc4);
- assert_eq!(encoder.current_chunk(), Some(&[0x10][..]));
+ assert_eq!(encoder.current_chunk(), &[0x10][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x20][..]));
+ assert_eq!(encoder.current_chunk(), &[0x20][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x30][..]));
+ assert_eq!(encoder.current_chunk(), &[0x30][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x40][..]));
+ assert_eq!(encoder.current_chunk(), &[0x40][..]);
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -423,19 +425,19 @@ mod tests {
let enc6 = TestArray([0x06]).encoder();
let mut encoder = Encoder6::new(enc1, enc2, enc3, enc4, enc5, enc6);
- assert_eq!(encoder.current_chunk(), Some(&[0x01][..]));
+ assert_eq!(encoder.current_chunk(), &[0x01][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x02][..]));
+ assert_eq!(encoder.current_chunk(), &[0x02][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x03][..]));
+ assert_eq!(encoder.current_chunk(), &[0x03][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x04][..]));
+ assert_eq!(encoder.current_chunk(), &[0x04][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x05][..]));
+ assert_eq!(encoder.current_chunk(), &[0x05][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x06][..]));
+ assert_eq!(encoder.current_chunk(), &[0x06][..]);
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -445,11 +447,11 @@ mod tests {
let enc2 = TestArray([0xDD, 0xCC]).encoder();
let mut encoder = Encoder2::new(enc1, enc2);
- assert_eq!(encoder.current_chunk(), Some(&[0xFF, 0xEE][..]));
+ assert_eq!(encoder.current_chunk(), &[0xFF, 0xEE][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0xDD, 0xCC][..]));
+ assert_eq!(encoder.current_chunk(), &[0xDD, 0xCC][..]);
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -460,13 +462,13 @@ mod tests {
let enc3 = TestArray([0x43, 0x44, 0x45]).encoder();
let mut encoder = Encoder3::new(enc1, enc2, enc3);
- assert_eq!(encoder.current_chunk(), Some(&[][..]));
+ assert!(encoder.current_chunk().is_empty());
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x42][..]));
+ assert_eq!(encoder.current_chunk(), &[0x42][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x43, 0x44, 0x45][..]));
+ assert_eq!(encoder.current_chunk(), &[0x43, 0x44, 0x45][..]);
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -477,13 +479,13 @@ mod tests {
let array_enc = TestArray([0x20, 0x21]).encoder();
let mut encoder = Encoder2::new(slice_enc, array_enc);
- assert_eq!(encoder.current_chunk(), Some(&[0x10, 0x11][..]));
+ assert_eq!(encoder.current_chunk(), &[0x10, 0x11][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x12, 0x13][..]));
+ assert_eq!(encoder.current_chunk(), &[0x12, 0x13][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x20, 0x21][..]));
+ assert_eq!(encoder.current_chunk(), &[0x20, 0x21][..]);
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -494,15 +496,15 @@ mod tests {
let slice_enc = SliceEncoder::without_length_prefix(slice);
let mut encoder = Encoder2::new(header, slice_enc);
- assert_eq!(encoder.current_chunk(), Some(&[0xFF, 0xFE][..]));
+ assert_eq!(encoder.current_chunk(), &[0xFF, 0xFE][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x01][..]));
+ assert_eq!(encoder.current_chunk(), &[0x01][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x02][..]));
+ assert_eq!(encoder.current_chunk(), &[0x02][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x03][..]));
+ assert_eq!(encoder.current_chunk(), &[0x03][..]);
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -517,21 +519,21 @@ mod tests {
let enc3 = SliceEncoder::without_length_prefix(slice3);
let mut encoder = Encoder3::new(enc1, enc2, enc3);
- assert_eq!(encoder.current_chunk(), Some(&[0xA1][..]));
+ assert_eq!(encoder.current_chunk(), &[0xA1][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0xA2][..]));
+ assert_eq!(encoder.current_chunk(), &[0xA2][..]);
// Skip the empty slice
assert!(encoder.advance());
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0xC1][..]));
+ assert_eq!(encoder.current_chunk(), &[0xC1][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0xC2][..]));
+ assert_eq!(encoder.current_chunk(), &[0xC2][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0xC3][..]));
+ assert_eq!(encoder.current_chunk(), &[0xC3][..]);
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -543,52 +545,58 @@ mod tests {
let footer = TestBytes(&[0xBE, 0xEF]).encoder();
let mut encoder = Encoder3::new(header, slice_enc, footer);
- assert_eq!(encoder.current_chunk(), Some(&[0xDE, 0xAD][..]));
+ assert_eq!(encoder.current_chunk(), &[0xDE, 0xAD][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x01, 0x02][..]));
+ assert_eq!(encoder.current_chunk(), &[0x01, 0x02][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0x03, 0x04][..]));
+ assert_eq!(encoder.current_chunk(), &[0x03, 0x04][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0xBE, 0xEF][..]));
+ assert_eq!(encoder.current_chunk(), &[0xBE, 0xEF][..]);
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
fn encode_compact_size() {
// 1-byte
let mut e = CompactSizeEncoder::new(0x10u64);
- assert_eq!(e.current_chunk(), Some(&[0x10][..]));
+ assert_eq!(e.current_chunk(), &[0x10][..]);
assert!(!e.advance());
- assert_eq!(e.current_chunk(), None);
+ assert!(e.current_chunk().is_empty());
let mut e = CompactSizeEncoder::new(0xFCu64);
- assert_eq!(e.current_chunk(), Some(&[0xFC][..]));
+ assert_eq!(e.current_chunk(), &[0xFC][..]);
assert!(!e.advance());
+ assert!(e.current_chunk().is_empty());
// 0xFD + u16
let mut e = CompactSizeEncoder::new(0x00FDu64);
- assert_eq!(e.current_chunk(), Some(&[0xFD, 0xFD, 0x00][..]));
+ assert_eq!(e.current_chunk(), &[0xFD, 0xFD, 0x00][..]);
assert!(!e.advance());
+ assert!(e.current_chunk().is_empty());
let mut e = CompactSizeEncoder::new(0x0FFFu64);
- assert_eq!(e.current_chunk(), Some(&[0xFD, 0xFF, 0x0F][..]));
+ assert_eq!(e.current_chunk(), &[0xFD, 0xFF, 0x0F][..]);
assert!(!e.advance());
+ assert!(e.current_chunk().is_empty());
// 0xFE + u32
let mut e = CompactSizeEncoder::new(0x0001_0000u64);
- assert_eq!(e.current_chunk(), Some(&[0xFE, 0x00, 0x00, 0x01, 0x00][..]));
+ assert_eq!(e.current_chunk(), &[0xFE, 0x00, 0x00, 0x01, 0x00][..]);
assert!(!e.advance());
+ assert!(e.current_chunk().is_empty());
let mut e = CompactSizeEncoder::new(0x0F0F_0F0Fu64);
- assert_eq!(e.current_chunk(), Some(&[0xFE, 0x0F, 0x0F, 0x0F, 0x0F][..]));
+ assert_eq!(e.current_chunk(), &[0xFE, 0x0F, 0x0F, 0x0F, 0x0F][..]);
assert!(!e.advance());
+ assert!(e.current_chunk().is_empty());
// 0xFF + u64
let mut e = CompactSizeEncoder::new(0x0000_F0F0_F0F0_F0E0u64);
assert_eq!(
e.current_chunk(),
- Some(&[0xFF, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00][..])
+ &[0xFF, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x00, 0x00][..]
);
assert!(!e.advance());
+ assert!(e.current_chunk().is_empty());
}
}
diff --git a/consensus_encoding/src/encode/mod.rs b/consensus_encoding/src/encode/mod.rs
index ecd34009..6e44e0ab 100644
--- a/consensus_encoding/src/encode/mod.rs
+++ b/consensus_encoding/src/encode/mod.rs
@@ -27,20 +27,19 @@ pub trait Encodable {
pub trait Encoder {
/// Yields the current encoded byteslice.
///
- /// Will always return the same value until [`Self::advance`] is called.
- ///
- /// Returns `None` if the encoder is exhausted. Once this method returns `None`,
- /// all subsequent calls will return `None`.
- fn current_chunk(&self) -> Option<&[u8]>;
+ /// Will always return the same value until [`Self::advance`] is called. May return an empty
+ /// list.
+ fn current_chunk(&self) -> &[u8];
/// Moves the encoder to its next state.
///
/// Does not need to be called when the encoder is first created. (In fact, if it
/// is called, this will discard the first chunk of encoded data.)
///
- /// Returns `true` if the next call to [`Self::current_chunk`] will return data.
- /// Returns `false` otherwise. It is fine to ignore the return value of this method
- /// and just call `current_chunk` to see if it works.
+ /// # Returns
+ ///
+ /// - `true` if the encoder has advanced to a new state and [`Self::current_chunk`] will return new data.
+ /// - `false` if the encoder is exhausted and has no more states.
fn advance(&mut self) -> bool;
}
@@ -57,7 +56,7 @@ macro_rules! encoder_newtype{
impl$(<$lt>)? $crate::Encoder for $name$(<$lt>)? {
#[inline]
- fn current_chunk(&self) -> Option<&[u8]> { self.0.current_chunk() }
+ fn current_chunk(&self) -> &[u8] { self.0.current_chunk() }
#[inline]
fn advance(&mut self) -> bool { self.0.advance() }
@@ -75,9 +74,11 @@ where
H: hashes::HashEngine,
{
let mut encoder = object.encoder();
- while let Some(sl) = encoder.current_chunk() {
- engine.input(sl);
- encoder.advance();
+ loop {
+ engine.input(encoder.current_chunk());
+ if !encoder.advance() {
+ break;
+ }
}
engine
}
@@ -90,9 +91,11 @@ where
{
let mut encoder = object.encoder();
let mut vec = Vec::new();
- while let Some(chunk) = encoder.current_chunk() {
- vec.extend_from_slice(chunk);
- encoder.advance();
+ loop {
+ vec.extend_from_slice(encoder.current_chunk());
+ if !encoder.advance() {
+ break;
+ }
}
vec
}
@@ -116,18 +119,20 @@ where
W: std::io::Write,
{
let mut encoder = object.encoder();
- while let Some(chunk) = encoder.current_chunk() {
- writer.write_all(chunk)?;
- encoder.advance();
+ loop {
+ writer.write_all(encoder.current_chunk())?;
+ if !encoder.advance() {
+ break;
+ }
}
Ok(())
}
impl<T: Encoder> Encoder for Option<T> {
- fn current_chunk(&self) -> Option<&[u8]> {
+ fn current_chunk(&self) -> &[u8] {
match self {
Some(encoder) => encoder.current_chunk(),
- None => None,
+ None => &[],
}
}
diff --git a/consensus_encoding/tests/composition.rs b/consensus_encoding/tests/composition.rs
index e0cf3b02..34673559 100644
--- a/consensus_encoding/tests/composition.rs
+++ b/consensus_encoding/tests/composition.rs
@@ -88,9 +88,11 @@ fn composition_chain() {
// Encode using the pull encoder.
let mut encoder = original.encoder();
let mut encoded_bytes = Vec::new();
- while let Some(chunk) = encoder.current_chunk() {
- encoded_bytes.extend_from_slice(chunk);
- encoder.advance();
+ loop {
+ encoded_bytes.extend_from_slice(encoder.current_chunk());
+ if !encoder.advance() {
+ break;
+ }
}
// Decode using the push decoder.
let mut decoder = CompositeData::decoder();
@@ -115,9 +117,11 @@ fn composition_nested() {
);
let mut encoded_bytes = Vec::new();
- while let Some(chunk) = encoder6.current_chunk() {
- encoded_bytes.extend_from_slice(chunk);
- encoder6.advance();
+ loop {
+ encoded_bytes.extend_from_slice(encoder6.current_chunk());
+ if !encoder6.advance() {
+ break;
+ }
}
assert_eq!(encoded_bytes, data);
@@ -325,16 +329,16 @@ fn empty_encoders() {
BytesEncoder::without_length_prefix(&bytes[2..]),
);
- assert_eq!(encoder.current_chunk(), Some(&[1, 2][..]));
+ assert_eq!(encoder.current_chunk(), &[1, 2][..]);
assert!(encoder.advance());
// Still have to advance over empty slice.
- assert_eq!(encoder.current_chunk(), Some(&[][..]));
+ assert!(encoder.current_chunk().is_empty());
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[3, 4][..]));
+ assert_eq!(encoder.current_chunk(), &[3, 4][..]);
assert!(!encoder.advance());
// Exhausted.
- assert!(encoder.current_chunk().is_none());
+ assert!(encoder.current_chunk().is_empty());
}
diff --git a/consensus_encoding/tests/encode.rs b/consensus_encoding/tests/encode.rs
index c6b157ce..d8f08d06 100644
--- a/consensus_encoding/tests/encode.rs
+++ b/consensus_encoding/tests/encode.rs
@@ -116,6 +116,6 @@ fn encode_newtype_lifetime_flexibility() {
let custom_encoder = CustomEncoder(BytesEncoder::without_length_prefix(test_data));
let no_lifetime_encoder = NoLifetimeEncoder(ArrayEncoder::without_length_prefix([1, 2, 3, 4]));
- assert_eq!(custom_encoder.current_chunk(), Some(test_data.as_slice()));
- assert_eq!(no_lifetime_encoder.current_chunk(), Some(&[1, 2, 3, 4][..]));
+ assert_eq!(custom_encoder.current_chunk(), test_data.as_slice());
+ assert_eq!(no_lifetime_encoder.current_chunk(), &[1, 2, 3, 4][..]);
}
diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs
index 06308241..79717adb 100644
--- a/primitives/src/transaction.rs
+++ b/primitives/src/transaction.rs
@@ -783,10 +783,8 @@ impl<'e> WitnessesEncoder<'e> {
#[cfg(feature = "alloc")]
impl Encoder for WitnessesEncoder<'_> {
#[inline]
- fn current_chunk(&self) -> Option<&[u8]> {
- // `advance` sets `cur_enc` to `None` once the slice encoder is completely exhausted.
- // `current_chunk` is required to return `None` if called after the encoder is exhausted.
- self.cur_enc.as_ref().and_then(WitnessEncoder::current_chunk)
+ fn current_chunk(&self) -> &[u8] {
+ self.cur_enc.as_ref().map(WitnessEncoder::current_chunk).unwrap_or_default()
}
#[inline]
@@ -807,7 +805,7 @@ impl Encoder for WitnessesEncoder<'_> {
// If advancing the current encoder failed, attempt to move to the next encoder.
if let Some(input) = self.inputs.first() {
*cur = input.witness.encoder();
- if cur.current_chunk().is_some() {
+ if !cur.current_chunk().is_empty() {
return true;
}
} else {
@@ -1720,21 +1718,19 @@ mod tests {
// The txid
assert_eq!(
encoder.current_chunk(),
- Some(
- &[
- 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,
- 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
- ][..]
- )
+ &[
+ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,
+ 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
+ ][..]
);
assert!(encoder.advance());
// The vout
- assert_eq!(encoder.current_chunk(), Some(&[1u8, 0, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8, 0, 0, 0][..]);
assert!(!encoder.advance());
// Exhausted
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -1744,19 +1740,19 @@ mod tests {
let mut encoder = out.encoder();
// The amount.
- assert_eq!(encoder.current_chunk(), Some(&[1, 0, 0, 0, 0, 0, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[1, 0, 0, 0, 0, 0, 0, 0][..]);
assert!(encoder.advance());
// The script pubkey length prefix.
- assert_eq!(encoder.current_chunk(), Some(&[3u8][..]));
+ assert_eq!(encoder.current_chunk(), &[3u8][..]);
assert!(encoder.advance());
// The script pubkey data.
- assert_eq!(encoder.current_chunk(), Some(&[1u8, 2, 3][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8, 2, 3][..]);
assert!(!encoder.advance());
// Exhausted
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -1769,29 +1765,27 @@ mod tests {
// The outpoint (same as tested above).
assert_eq!(
encoder.current_chunk(),
- Some(
- &[
- 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,
- 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
- ][..]
- )
+ &[
+ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,
+ 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
+ ][..]
);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[1u8, 0, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8, 0, 0, 0][..]);
assert!(encoder.advance());
// The script sig
- assert_eq!(encoder.current_chunk(), Some(&[3u8][..]));
+ assert_eq!(encoder.current_chunk(), &[3u8][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[1u8, 2, 3][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8, 2, 3][..]);
assert!(encoder.advance());
// The sequence
- assert_eq!(encoder.current_chunk(), Some(&[0xffu8, 0xff, 0xff, 0xff][..]));
+ assert_eq!(encoder.current_chunk(), &[0xffu8, 0xff, 0xff, 0xff][..]);
assert!(!encoder.advance());
// Exhausted
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -1807,57 +1801,55 @@ mod tests {
let mut encoder = tx.encoder();
// The version
- assert_eq!(encoder.current_chunk(), Some(&[2u8, 0, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[2u8, 0, 0, 0][..]);
assert!(encoder.advance());
// The segwit marker and flag
- assert_eq!(encoder.current_chunk(), Some(&[0u8, 1][..]));
+ assert_eq!(encoder.current_chunk(), &[0u8, 1][..]);
assert!(encoder.advance());
// The input (same as tested above) but with vec length prefix.
- assert_eq!(encoder.current_chunk(), Some(&[1u8][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8][..]);
assert!(encoder.advance());
assert_eq!(
encoder.current_chunk(),
- Some(
- &[
- 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,
- 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
- ][..]
- )
+ &[
+ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,
+ 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
+ ][..]
);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[1u8, 0, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8, 0, 0, 0][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[3u8][..]));
+ assert_eq!(encoder.current_chunk(), &[3u8][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[1u8, 2, 3][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8, 2, 3][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0xffu8, 0xff, 0xff, 0xff][..]));
+ assert_eq!(encoder.current_chunk(), &[0xffu8, 0xff, 0xff, 0xff][..]);
assert!(encoder.advance());
// The output (same as tested above) but with vec length prefix.
- assert_eq!(encoder.current_chunk(), Some(&[1u8][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[1, 0, 0, 0, 0, 0, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[1, 0, 0, 0, 0, 0, 0, 0][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[3u8][..]));
+ assert_eq!(encoder.current_chunk(), &[3u8][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[1u8, 2, 3][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8, 2, 3][..]);
assert!(encoder.advance());
// The witness
- assert_eq!(encoder.current_chunk(), Some(&[1u8][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[3u8, 1, 2, 3][..]));
+ assert_eq!(encoder.current_chunk(), &[3u8, 1, 2, 3][..]);
assert!(encoder.advance());
// The lock time.
- assert_eq!(encoder.current_chunk(), Some(&[0, 0, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[0, 0, 0, 0][..]);
assert!(!encoder.advance());
// Exhausted
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
@@ -1877,53 +1869,52 @@ mod tests {
let mut encoder = tx.encoder();
// The version
- assert_eq!(encoder.current_chunk(), Some(&[2u8, 0, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[2u8, 0, 0, 0][..]);
assert!(encoder.advance());
// Advance past the optional segwit bytes encoder.
assert!(encoder.advance());
// The input (same as tested above) but with vec length prefix.
- assert_eq!(encoder.current_chunk(), Some(&[1u8][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8][..]);
assert!(encoder.advance());
assert_eq!(
encoder.current_chunk(),
- Some(
- &[
- 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,
- 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
- ][..]
- )
+ &[
+ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,
+ 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
+ ][..]
+
);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[1u8, 0, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8, 0, 0, 0][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[3u8][..]));
+ assert_eq!(encoder.current_chunk(), &[3u8][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[1u8, 2, 3][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8, 2, 3][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0xffu8, 0xff, 0xff, 0xff][..]));
+ assert_eq!(encoder.current_chunk(), &[0xffu8, 0xff, 0xff, 0xff][..]);
assert!(encoder.advance());
// The output (same as tested above) but with vec length prefix.
- assert_eq!(encoder.current_chunk(), Some(&[1u8][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[1, 0, 0, 0, 0, 0, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[1, 0, 0, 0, 0, 0, 0, 0][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[3u8][..]));
+ assert_eq!(encoder.current_chunk(), &[3u8][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[1u8, 2, 3][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8, 2, 3][..]);
assert!(encoder.advance());
// Advance past the optional witnesses encoder.
assert!(encoder.advance());
// The lock time.
- assert_eq!(encoder.current_chunk(), Some(&[0, 0, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[0, 0, 0, 0][..]);
assert!(!encoder.advance());
// Exhausted
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
// FIXME: Move all these encoding tests to a single file in `primitives/tests/`.
@@ -1959,93 +1950,87 @@ mod tests {
// The block header, 6 encoders, 1 chunk per encoder.
// The block version.
- assert_eq!(encoder.current_chunk(), Some(&[2u8, 0, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[2u8, 0, 0, 0][..]);
assert!(encoder.advance());
// The previous block's blockhash.
assert_eq!(
encoder.current_chunk(),
- Some(
- &[
- 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171,
- 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171
- ][..]
- )
+ &[
+ 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171,
+ 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171
+ ][..]
);
assert!(encoder.advance());
// The merkle root hash.
assert_eq!(
encoder.current_chunk(),
- Some(
- &[
- 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205,
- 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205
- ][..]
- )
+ &[
+ 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205,
+ 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205
+ ][..]
);
assert!(encoder.advance());
// The block time.
- assert_eq!(encoder.current_chunk(), Some(&[80, 195, 137, 98][..]));
+ assert_eq!(encoder.current_chunk(), &[80, 195, 137, 98][..]);
assert!(encoder.advance());
// The target (bits).
- assert_eq!(encoder.current_chunk(), Some(&[239, 190, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[239, 190, 0, 0][..]);
assert!(encoder.advance());
// The nonce.
- assert_eq!(encoder.current_chunk(), Some(&[254, 202, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[254, 202, 0, 0][..]);
assert!(encoder.advance());
// The transaction list length prefix.
- assert_eq!(encoder.current_chunk(), Some(&[1u8][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8][..]);
assert!(encoder.advance());
// The transaction (same as tested above).
// The version
- assert_eq!(encoder.current_chunk(), Some(&[2u8, 0, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[2u8, 0, 0, 0][..]);
assert!(encoder.advance());
// The segwit marker and flag
- assert_eq!(encoder.current_chunk(), Some(&[0u8, 1][..]));
+ assert_eq!(encoder.current_chunk(), &[0u8, 1][..]);
assert!(encoder.advance());
// The input (same as tested above) but with vec length prefix.
- assert_eq!(encoder.current_chunk(), Some(&[1u8][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8][..]);
assert!(encoder.advance());
assert_eq!(
encoder.current_chunk(),
- Some(
- &[
- 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,
- 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
- ][..]
- )
+ &[
+ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,
+ 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
+ ][..]
);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[1u8, 0, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8, 0, 0, 0][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[3u8][..]));
+ assert_eq!(encoder.current_chunk(), &[3u8][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[1u8, 2, 3][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8, 2, 3][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[0xffu8, 0xff, 0xff, 0xff][..]));
+ assert_eq!(encoder.current_chunk(), &[0xffu8, 0xff, 0xff, 0xff][..]);
assert!(encoder.advance());
// The output (same as tested above) but with vec length prefix.
- assert_eq!(encoder.current_chunk(), Some(&[1u8][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[1, 0, 0, 0, 0, 0, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[1, 0, 0, 0, 0, 0, 0, 0][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[3u8][..]));
+ assert_eq!(encoder.current_chunk(), &[3u8][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[1u8, 2, 3][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8, 2, 3][..]);
assert!(encoder.advance());
// The witness
- assert_eq!(encoder.current_chunk(), Some(&[1u8][..]));
+ assert_eq!(encoder.current_chunk(), &[1u8][..]);
assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), Some(&[3u8, 1, 2, 3][..]));
+ assert_eq!(encoder.current_chunk(), &[3u8, 1, 2, 3][..]);
assert!(encoder.advance());
// The lock time.
- assert_eq!(encoder.current_chunk(), Some(&[0, 0, 0, 0][..]));
+ assert_eq!(encoder.current_chunk(), &[0, 0, 0, 0][..]);
assert!(!encoder.advance());
// Exhausted
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
diff --git a/primitives/src/witness.rs b/primitives/src/witness.rs
index 1210cf58..f13c4fad 100644
--- a/primitives/src/witness.rs
+++ b/primitives/src/witness.rs
@@ -293,7 +293,7 @@ impl Encodable for Witness {
impl Encoder for WitnessEncoder<'_> {
#[inline]
- fn current_chunk(&self) -> Option<&[u8]> { self.0.current_chunk() }
+ fn current_chunk(&self) -> &[u8] { self.0.current_chunk() }
#[inline]
fn advance(&mut self) -> bool { self.0.advance() }
@@ -1179,13 +1179,13 @@ mod test {
// Should have length prefix chunk, then the content slice, then exhausted.
let mut encoder = witness.encoder();
- assert_eq!(encoder.current_chunk(), Some(&[2u8][..]));
+ assert_eq!(encoder.current_chunk(), &[2u8][..]);
assert!(encoder.advance());
// We don't encode one element at a time, rather we encode the whole content slice at once.
- assert_eq!(encoder.current_chunk(), Some(&[3u8, 1, 2, 3, 2, 4, 5][..]));
+ assert_eq!(encoder.current_chunk(), &[3u8, 1, 2, 3, 2, 4, 5][..]);
assert!(!encoder.advance());
- assert_eq!(encoder.current_chunk(), None);
+ assert!(encoder.current_chunk().is_empty());
}
#[test]
Why this scored 18/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.