Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions neqo-common/src/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,17 @@ impl Encoder<Vec<u8>> {
Self::default()
}

/// Skip the first `n` bytes from the encoder buffer without copying.
/// This advances the internal offset, making those bytes inaccessible.
///
/// # Panics
///
/// Panics if `n` is greater than the current length of the encoder.
pub fn skip(&mut self, n: usize) {
assert!(n <= self.len(), "Cannot skip beyond buffer length");
self.start += n;
Comment thread
larseggert marked this conversation as resolved.
}
Comment thread
larseggert marked this conversation as resolved.
Comment thread
larseggert marked this conversation as resolved.
Comment on lines +428 to +437
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation for skip() should clarify that this method is only available for Encoder<Vec<u8>>, not for generic Encoder<B> where B: Buffer. This is important because the method is defined in an impl Encoder<Vec<u8>> block, not impl<B: Buffer> Encoder<B>.

Copilot uses AI. Check for mistakes.

/// Static helper function for previewing the results of encoding without doing it.
///
/// # Panics
Expand Down Expand Up @@ -1195,6 +1206,26 @@ mod tests {
assert_eq!(Buffer::position(&buf), 0);
}

#[test]
fn encoder_skip() {
let mut enc = Encoder::from_hex("010203040506");

enc.skip(2);
assert_eq!(enc.len(), 4);
assert_eq!(enc.as_ref(), &[0x03, 0x04, 0x05, 0x06]);

enc.skip(4);
assert_eq!(enc.len(), 0);
assert!(enc.is_empty());
}

#[test]
#[should_panic(expected = "Cannot skip beyond buffer length")]
fn encoder_skip_too_much() {
let mut enc = Encoder::from_hex("0102");
enc.skip(3);
}

/// [`Encoder::as_decoder`] should only expose the bytes actively encoded through this
/// [`Encoder`], not all bytes of the underlying [`Buffer`].
#[test]
Expand Down
14 changes: 9 additions & 5 deletions neqo-qpack/src/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use std::fmt::{self, Display, Formatter};

use neqo_common::{qdebug, Header};
use neqo_common::{qdebug, Encoder, Header};
use neqo_transport::{Connection, StreamId};

use crate::{
Expand All @@ -28,7 +28,7 @@ pub struct Decoder {
table: HeaderTable,
acked_inserts: u64,
max_entries: u64,
send_buf: Data,
send_buf: Encoder,
local_stream_id: Option<StreamId>,
max_table_size: u64,
max_blocked_streams: usize,
Expand All @@ -43,7 +43,7 @@ impl Decoder {
#[must_use]
pub fn new(qpack_settings: &Settings) -> Self {
qdebug!("Decoder: creating a new qpack decoder");
let mut send_buf = Data::default();
let mut send_buf = Encoder::default();
send_buf.encode_varint(QPACK_UNI_STREAM_TYPE_DECODER);
let max_blocked_streams = usize::from(qpack_settings.max_blocked_streams);
Self {
Expand Down Expand Up @@ -179,11 +179,15 @@ impl Decoder {
let r = conn
.stream_send(
self.local_stream_id.ok_or(Error::Internal)?,
&self.send_buf[..],
self.send_buf.as_ref(),
)
.map_err(|_| Error::DecoderStream)?;
qdebug!("[{self}] {r} bytes sent");
self.send_buf.read(r);
if r < self.send_buf.len() {
self.send_buf.skip(r);
} else {
self.send_buf = Encoder::default();
}
Comment thread
larseggert marked this conversation as resolved.
Outdated
}
Ok(())
}
Expand Down
17 changes: 9 additions & 8 deletions neqo-qpack/src/decoder_instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use neqo_transport::StreamId;

use crate::{
prefix::{DECODER_HEADER_ACK, DECODER_INSERT_COUNT_INCREMENT, DECODER_STREAM_CANCELLATION},
qpack_send_buf::Data,
qpack_send_buf::Encoder,
reader::{IntReader, ReadByte},
Res,
};
Expand Down Expand Up @@ -44,7 +44,7 @@ impl DecoderInstruction {
}
}

pub(crate) fn marshal(&self, enc: &mut Data) {
pub(crate) fn marshal<T: Encoder>(&self, enc: &mut T) {
match self {
Self::InsertCountIncrement { increment } => {
enc.encode_prefixed_encoded_int(DECODER_INSERT_COUNT_INCREMENT, *increment);
Expand Down Expand Up @@ -144,16 +144,17 @@ impl DecoderInstructionReader {
#[cfg_attr(coverage_nightly, coverage(off))]
mod test {

use neqo_common::Encoder;
use neqo_transport::StreamId;

use super::{Data, DecoderInstruction, DecoderInstructionReader};
use super::{DecoderInstruction, DecoderInstructionReader};
use crate::{reader::test_receiver::TestReceiver, Error};

fn test_encoding_decoding(instruction: DecoderInstruction) {
let mut buf = Data::default();
let mut buf = Encoder::default();
instruction.marshal(&mut buf);
let mut test_receiver: TestReceiver = TestReceiver::default();
test_receiver.write(&buf);
test_receiver.write(buf.as_ref());
let mut decoder = DecoderInstructionReader::new();
assert_eq!(
decoder.read_instructions(&mut test_receiver).unwrap(),
Expand Down Expand Up @@ -182,18 +183,18 @@ mod test {
}

fn test_encoding_decoding_slow_reader(instruction: DecoderInstruction) {
let mut buf = Data::default();
let mut buf = Encoder::default();
instruction.marshal(&mut buf);
let mut test_receiver: TestReceiver = TestReceiver::default();
let mut decoder = DecoderInstructionReader::new();
for i in 0..buf.len() - 1 {
test_receiver.write(&buf[i..=i]);
test_receiver.write(&buf.as_ref()[i..=i]);
assert_eq!(
decoder.read_instructions(&mut test_receiver),
Err(Error::NeedMoreData)
);
}
test_receiver.write(&buf[buf.len() - 1..buf.len()]);
test_receiver.write(&buf.as_ref()[buf.len() - 1..buf.len()]);
assert_eq!(
decoder.read_instructions(&mut test_receiver).unwrap(),
instruction
Expand Down
21 changes: 10 additions & 11 deletions neqo-qpack/src/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ use crate::{
encoder_instructions::EncoderInstruction,
header_block::HeaderEncoder,
qlog,
qpack_send_buf::Data,
reader::ReceiverConnWrapper,
stats::Stats,
table::{HeaderTable, LookupResult, ADDITIONAL_TABLE_ENTRY_SIZE},
Expand Down Expand Up @@ -281,14 +280,14 @@ impl Encoder {
return Err(Error::DynamicTableFull);
}

let mut buf = Data::default();
let mut buf = neqo_common::Encoder::default();
EncoderInstruction::InsertWithNameLiteral { name, value }
.marshal(&mut buf, self.use_huffman);

let stream_id = self.local_stream.stream_id().ok_or(Error::Internal)?;

let sent = conn
.stream_send_atomic(stream_id, &buf)
.stream_send_atomic(stream_id, buf.as_ref())
.map_err(|e| map_stream_send_atomic_error(&e))?;
if !sent {
return Err(Error::EncoderStreamBlocked);
Expand Down Expand Up @@ -321,9 +320,9 @@ impl Encoder {
if cap < self.table.capacity() && !self.table.can_evict_to(cap) {
return Err(Error::DynamicTableFull);
}
let mut buf = Data::default();
let mut buf = neqo_common::Encoder::default();
EncoderInstruction::Capacity { value: cap }.marshal(&mut buf, self.use_huffman);
if !conn.stream_send_atomic(stream_id, &buf)? {
if !conn.stream_send_atomic(stream_id, buf.as_ref())? {
return Err(Error::EncoderStreamBlocked);
}
if self.table.set_capacity(cap).is_err() {
Expand Down Expand Up @@ -351,9 +350,9 @@ impl Encoder {
Ok(())
}
LocalStreamState::Uninitialized(stream_id) => {
let mut buf = Data::default();
let mut buf = neqo_common::Encoder::default();
buf.encode_varint(QPACK_UNI_STREAM_TYPE_ENCODER);
if !conn.stream_send_atomic(stream_id, &buf[..])? {
if !conn.stream_send_atomic(stream_id, buf.as_ref())? {
return Err(Error::EncoderStreamBlocked);
}
self.local_stream = LocalStreamState::Initialized(stream_id);
Expand Down Expand Up @@ -596,7 +595,7 @@ mod tests {
let buf = self
.encoder
.encode_header_block(&mut self.conn, headers, stream_id);
assert_eq!(&buf[..], expected_encoding);
assert_eq!(buf.as_ref(), expected_encoding);
self.send_instructions(inst);
}

Expand Down Expand Up @@ -822,7 +821,7 @@ mod tests {
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &t.headers, STREAM_1);
assert_eq!(&buf[..], t.header_block);
assert_eq!(buf.as_ref(), t.header_block);
encoder.send_instructions(t.encoder_inst);
}
}
Expand Down Expand Up @@ -896,7 +895,7 @@ mod tests {
let buf = encoder
.encoder
.encode_header_block(&mut encoder.conn, &t.headers, STREAM_1);
assert_eq!(&buf[..], t.header_block);
assert_eq!(buf.as_ref(), t.header_block);
encoder.send_instructions(t.encoder_inst);
}
}
Expand Down Expand Up @@ -968,7 +967,7 @@ mod tests {
&[Header::new("content-length", "1234")],
STREAM_1,
);
assert_eq!(&buf[..], ENCODE_INDEXED_REF_DYNAMIC);
assert_eq!(buf.as_ref(), ENCODE_INDEXED_REF_DYNAMIC);
encoder.send_instructions(&[]);

// insert "content-length: 12345 which will fail because the entry in the table cannot be
Expand Down
16 changes: 8 additions & 8 deletions neqo-qpack/src/encoder_instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
ENCODER_CAPACITY, ENCODER_DUPLICATE, ENCODER_INSERT_WITH_NAME_LITERAL,
ENCODER_INSERT_WITH_NAME_REF_DYNAMIC, ENCODER_INSERT_WITH_NAME_REF_STATIC, NO_PREFIX,
},
qpack_send_buf::Data,
qpack_send_buf::Encoder,
reader::{IntReader, LiteralReader, ReadByte, Reader},
Res,
};
Expand Down Expand Up @@ -52,7 +52,7 @@ pub enum EncoderInstruction<'a> {
}

impl EncoderInstruction<'_> {
pub(crate) fn marshal(&self, enc: &mut Data, use_huffman: bool) {
pub(crate) fn marshal<T: Encoder>(&self, enc: &mut T, use_huffman: bool) {
match self {
Self::Capacity { value } => {
enc.encode_prefixed_encoded_int(ENCODER_CAPACITY, *value);
Expand Down Expand Up @@ -297,14 +297,14 @@ impl EncoderInstructionReader {
#[cfg_attr(coverage_nightly, coverage(off))]
mod test {

use super::{Data, EncoderInstruction, EncoderInstructionReader};
use super::{EncoderInstruction, EncoderInstructionReader};
use crate::{reader::test_receiver::TestReceiver, Error};

fn test_encoding_decoding(instruction: &EncoderInstruction, use_huffman: bool) {
let mut buf = Data::default();
let mut buf = neqo_common::Encoder::default();
instruction.marshal(&mut buf, use_huffman);
let mut test_receiver: TestReceiver = TestReceiver::default();
test_receiver.write(&buf);
test_receiver.write(buf.as_ref());
let mut reader = EncoderInstructionReader::new();
assert_eq!(
reader.read_instructions(&mut test_receiver).unwrap(),
Expand Down Expand Up @@ -395,18 +395,18 @@ mod test {
}

fn test_encoding_decoding_slow_reader(instruction: &EncoderInstruction, use_huffman: bool) {
let mut buf = Data::default();
let mut buf = neqo_common::Encoder::default();
instruction.marshal(&mut buf, use_huffman);
let mut test_receiver: TestReceiver = TestReceiver::default();
let mut decoder = EncoderInstructionReader::new();
for i in 0..buf.len() - 1 {
test_receiver.write(&buf[i..=i]);
test_receiver.write(&buf.as_ref()[i..=i]);
assert_eq!(
decoder.read_instructions(&mut test_receiver),
Err(Error::NeedMoreData)
);
}
test_receiver.write(&buf[buf.len() - 1..buf.len()]);
test_receiver.write(&buf.as_ref()[buf.len() - 1..buf.len()]);
assert_eq!(
decoder.read_instructions(&mut test_receiver).unwrap(),
instruction.into()
Expand Down
10 changes: 5 additions & 5 deletions neqo-qpack/src/header_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ use crate::{
HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC_POST, HEADER_FIELD_LITERAL_NAME_REF_STATIC,
NO_PREFIX,
},
qpack_send_buf::Data,
qpack_send_buf::Encoder as _,
reader::{parse_utf8, ReceiverBufferWrapper},
table::HeaderTable,
Error, Res,
};

#[derive(Default, Debug, PartialEq, Eq)]
pub struct HeaderEncoder {
buf: Data,
buf: neqo_common::Encoder,
base: u64,
use_huffman: bool,
max_entries: u64,
Expand All @@ -44,7 +44,7 @@ impl Display for HeaderEncoder {
impl HeaderEncoder {
pub fn new(base: u64, use_huffman: bool, max_entries: u64) -> Self {
Self {
buf: Data::default(),
buf: neqo_common::Encoder::default(),
base,
use_huffman,
max_entries,
Expand Down Expand Up @@ -139,14 +139,14 @@ impl HeaderEncoder {
.encode_prefixed_encoded_int(NO_PREFIX, enc_insert_cnt);
self.buf.encode_prefixed_encoded_int(prefix, delta);

self.buf.write_bytes(&tmp);
self.buf.encode(tmp.as_ref());
Comment thread
larseggert marked this conversation as resolved.
Outdated
}
}

impl Deref for HeaderEncoder {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.buf
self.buf.as_ref()
}
}

Expand Down
Loading
Loading