Skip to content

Commit 9d5ff8a

Browse files
committed
Add prefix support to BytesEncoder
Done in preparation for adding support to `primitives` for encoding scripts. Enable encoding with the compact size length prefix. N.B. If the encoder is constructed with an empty slice the first call to `current_chunk` will return `Some([])`.
1 parent e0b9d39 commit 9d5ff8a

File tree

4 files changed

+56
-6
lines changed

4 files changed

+56
-6
lines changed

Cargo-minimal.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ dependencies = [
209209
name = "consensus-encoding"
210210
version = "0.0.0"
211211
dependencies = [
212+
"bitcoin-internals",
212213
"bitcoin_hashes 0.16.0",
213214
]
214215

Cargo-recent.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ dependencies = [
211211
name = "consensus-encoding"
212212
version = "0.0.0"
213213
dependencies = [
214+
"bitcoin-internals",
214215
"bitcoin_hashes 0.16.0",
215216
]
216217

consensus_encoding/Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,12 @@ exclude = ["tests", "contrib"]
1414

1515
[features]
1616
default = ["std"]
17-
std = ["alloc"]
18-
alloc = []
17+
std = ["alloc", "internals/std"]
18+
alloc = ["internals/alloc"]
1919

2020
[dependencies]
2121
hashes = { package = "bitcoin_hashes", path = "../hashes", default-features = false }
22+
internals = { package = "bitcoin-internals", path = "../internals" }
2223

2324
[package.metadata.docs.rs]
2425
all-features = true

consensus_encoding/src/encode/encoders.rs

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,49 @@
1111
//! For implementing these newtypes, we provide the [`encoder_newtype`] macro.
1212
//!
1313
14+
use internals::array_vec::ArrayVec;
15+
use internals::compact_size;
16+
1417
use super::Encoder;
1518

19+
/// The maximum length of a compact size encoding.
20+
const SIZE: usize = compact_size::MAX_ENCODING_SIZE;
21+
1622
/// An encoder for a single byte slice.
1723
pub struct BytesEncoder<'sl> {
1824
sl: Option<&'sl [u8]>,
25+
compact_size: Option<ArrayVec<u8, SIZE>>,
1926
}
2027

2128
impl<'sl> BytesEncoder<'sl> {
2229
/// Constructs a byte encoder which encodes the given byte slice, with no length prefix.
23-
pub fn without_length_prefix(sl: &'sl [u8]) -> Self { Self { sl: Some(sl) } }
30+
pub fn without_length_prefix(sl: &'sl [u8]) -> Self {
31+
Self { sl: Some(sl), compact_size: None }
32+
}
33+
34+
/// Constructs a byte encoder which encodes the given byte slice, with the length prefix.
35+
pub fn with_length_prefix(sl: &'sl [u8]) -> Self {
36+
Self { sl: Some(sl), compact_size: Some(compact_size::encode(sl.len())) }
37+
}
2438
}
2539

2640
impl<'e, 'sl> Encoder<'e> for BytesEncoder<'sl> {
27-
fn current_chunk(&self) -> Option<&[u8]> { self.sl }
41+
fn current_chunk(&self) -> Option<&[u8]> {
42+
if let Some(compact_size) = self.compact_size.as_ref() {
43+
Some(compact_size)
44+
} else {
45+
self.sl
46+
}
47+
}
2848

2949
fn advance(&mut self) -> bool {
30-
self.sl = None;
31-
false
50+
if self.compact_size.is_some() {
51+
self.compact_size = None;
52+
true
53+
} else {
54+
self.sl = None;
55+
false
56+
}
3257
}
3358
}
3459

@@ -192,4 +217,26 @@ mod tests {
192217

193218
assert_eq!(got, obj);
194219
}
220+
221+
#[test]
222+
fn encode_byte_slice_with_prefix() {
223+
let obj = [1u8, 2, 3];
224+
225+
let encoder = BytesEncoder::with_length_prefix(&obj);
226+
let got = run_encoder(encoder);
227+
228+
let want = [3u8, 1, 2, 3];
229+
assert_eq!(got, want);
230+
}
231+
232+
#[test]
233+
fn encode_empty_byte_slice_with_prefix() {
234+
let obj = [];
235+
236+
let encoder = BytesEncoder::with_length_prefix(&obj);
237+
let got = run_encoder(encoder);
238+
239+
let want = [0u8];
240+
assert_eq!(got, want);
241+
}
195242
}

0 commit comments

Comments
 (0)