Skip to content

Commit c15b2d3

Browse files
authored
pref: improve decode_raw (#34)
* improve decode_raw * add CHANGELOG * fix link in CHANGELOG
1 parent 9d622be commit c15b2d3

File tree

2 files changed

+25
-13
lines changed

2 files changed

+25
-13
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Changed
11+
12+
- Improve `decode_raw` performance ([#34])
13+
14+
[#34]: https://github.com/alloy-rs/rlp/pull/34
15+
1016
## [0.3.8] - 2024-08-05
1117

1218
### Added

crates/rlp/src/header.rs

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,15 @@ impl Header {
106106

107107
/// Extracts the next payload from the given buffer, advancing it.
108108
///
109+
/// The returned `PayloadView` provides a structured view of the payload, allowing for efficient
110+
/// parsing of nested items without unnecessary allocations.
111+
///
109112
/// # Errors
110113
///
111-
/// Returns an error if the buffer is too short, the header is invalid or one of the headers one
112-
/// level deeper is invalid.
114+
/// Returns an error if:
115+
/// - The buffer is too short
116+
/// - The header is invalid
117+
/// - Any nested headers (for list items) are invalid
113118
#[inline]
114119
pub fn decode_raw<'a>(buf: &mut &'a [u8]) -> Result<PayloadView<'a>> {
115120
let Self { list, payload_length } = Self::decode(buf)?;
@@ -122,17 +127,18 @@ impl Header {
122127

123128
let mut items = alloc::vec::Vec::new();
124129
while !payload.is_empty() {
125-
// decode the next header without advancing in the payload
126-
let Self { payload_length, .. } = Self::decode(&mut &payload[..])?;
127-
// the length of the RLP encoding is the length of the header plus its payload length
128-
// if payload length is 1 and the first byte is in [0x00, 0x7F], then there is no header
129-
let rlp_length = if payload_length == 1 && payload[0] <= 0x7F {
130-
1
131-
} else {
132-
payload_length + crate::length_of_length(payload_length)
133-
};
134-
items.push(&payload[..rlp_length]);
135-
payload.advance(rlp_length);
130+
// store the start of the current item for later slice creation
131+
let item_start = payload;
132+
133+
// decode the header of the next RLP item, advancing the payload
134+
let Self { payload_length, .. } = Self::decode(&mut payload)?;
135+
// SAFETY: this is already checked in `decode`
136+
unsafe { advance_unchecked(&mut payload, payload_length) };
137+
138+
// calculate the total length of the item (header + payload) by subtracting the
139+
// remaining payload length from the initial length
140+
let item_length = item_start.len() - payload.len();
141+
items.push(&item_start[..item_length]);
136142
}
137143

138144
Ok(PayloadView::List(items))

0 commit comments

Comments
 (0)