rlp/rlp_encoder.cpp¶
Namespaces¶
| Name |
|---|
| rlp |
Source code¶
#include <rlp/rlp_encoder.hpp> // Direct include
#include <rlp/endian.hpp> // Direct include
#include <cstring> // For std::memcpy
namespace rlp {
namespace { // Anonymous namespace for internal helpers
// Encodes just the header bytes into a temporary buffer
EncodingResult<Bytes> encode_header_bytes(bool list, size_t payload_size_bytes) noexcept {
Bytes header_bytes;
header_bytes.reserve(1 + sizeof(uint64_t)); // Max possible header size
uint8_t short_offset = list ? kShortListOffset : kShortStringOffset;
uint8_t long_offset = list ? kLongListOffset : kLongStringOffset;
if ( payload_size_bytes <= kMaxShortStringLen ) { // 55 bytes
header_bytes.push_back(static_cast<uint8_t>(short_offset + payload_size_bytes));
} else {
Bytes len_be = endian::to_big_compact(static_cast<uint64_t>(payload_size_bytes));
if ( len_be.length() > 8 ) {
// RLP spec limits length field to 8 bytes
return EncodingError::kPayloadTooLarge;
}
header_bytes.reserve(header_bytes.size() + kLongPrefixByteSize + len_be.length());
header_bytes.push_back(static_cast<uint8_t>(long_offset + len_be.length()));
header_bytes.append(len_be.data(), len_be.length());
}
return header_bytes;
}
} // namespace
// --- Public Method Implementations ---
EncodingOperationResult RlpEncoder::add(ByteView bytes) noexcept {
// Handle single byte literal case
if ( bytes.length() == 1 && static_cast<uint8_t>(bytes[0]) < kRlpSingleByteThreshold ) {
buffer_.push_back(bytes[0]);
} else {
BOOST_OUTCOME_TRY(auto header, encode_header_bytes(false, bytes.length()));
size_t old_size = buffer_.size();
buffer_.resize(old_size + header.length() + bytes.length());
std::memcpy(buffer_.data() + old_size, header.data(), header.length());
std::memcpy(buffer_.data() + old_size + header.length(), bytes.data(), bytes.length());
}
return outcome::success();
}
EncodingOperationResult RlpEncoder::AddRaw(ByteView bytes) noexcept {
if ( bytes.empty() ) {
return EncodingError::kEmptyInput;
}
buffer_.append(bytes);
return outcome::success();
}
// Explicit overload for uint256
EncodingOperationResult RlpEncoder::add(const intx::uint256& n) noexcept {
if ( n == 0 ) {
buffer_.push_back(kEmptyStringCode);
} else if ( n < kRlpSingleByteThreshold ) {
buffer_.push_back(static_cast<uint8_t>(n));
} else {
const Bytes be{endian::to_big_compact(n)};
BOOST_OUTCOME_TRY(auto header, encode_header_bytes(false, be.length()));
size_t old_size = buffer_.size();
buffer_.resize(old_size + header.length() + be.length());
std::memcpy(buffer_.data() + old_size, header.data(), header.length());
std::memcpy(buffer_.data() + old_size + header.length(), be.data(), be.length());
}
return outcome::success();
}
EncodingOperationResult RlpEncoder::BeginList() noexcept {
list_start_positions_.push_back(buffer_.size());
return outcome::success();
}
EncodingOperationResult RlpEncoder::EndList() noexcept {
if ( list_start_positions_.empty() ) {
return EncodingError::kUnmatchedEndList;
}
size_t start_pos = list_start_positions_.back();
list_start_positions_.pop_back();
size_t payload_len = buffer_.size() - start_pos;
BOOST_OUTCOME_TRY(auto header, encode_header_bytes(true, payload_len));
// Insert header at start_pos by making room and copying
buffer_.insert(buffer_.begin() + start_pos, header.begin(), header.end());
return outcome::success();
}
EncodingResult<const Bytes*> RlpEncoder::GetBytes() const noexcept {
if ( !list_start_positions_.empty() ) {
return EncodingError::kUnclosedList;
}
return &buffer_;
}
EncodingResult<Bytes*> RlpEncoder::GetBytes() noexcept {
if ( !list_start_positions_.empty() ) {
return EncodingError::kUnclosedList;
}
return &buffer_;
}
EncodingResult<Bytes> RlpEncoder::MoveBytes() noexcept {
if ( !list_start_positions_.empty() ) {
return EncodingError::kUnclosedList;
}
return std::move(buffer_);
}
void RlpEncoder::clear() noexcept {
buffer_.clear();
list_start_positions_.clear();
}
} // namespace rlp
Updated on 2026-04-13 at 23:22:46 -0700