use std::{
fmt::{self, Debug, Formatter, Write},
io::{self, Cursor},
};
usecrate::hex_with_len;
pubconst MAX_VARINT: u64 = (1 << 62) - 1;
/// Decoder is a view into a byte array that has a read offset. Use it for parsing. pubstruct Decoder<'a> {
buf: &'a [u8],
offset: usize,
}
impl<'a> Decoder<'a> { /// Make a new view of the provided slice. #[must_use] pubconstfn new(buf: &'a [u8]) -> Self { Self { buf, offset: 0 }
}
/// Get the number of bytes remaining until the end. #[must_use] pubconstfn remaining(&self) -> usize { self.buf.len() - self.offset
}
/// The number of bytes from the underlying slice that have been decoded. #[must_use] pubconstfn offset(&self) -> usize { self.offset
}
/// Skip n bytes. /// /// # Panics /// /// If the remaining quantity is less than `n`. pubfn skip(&mutself, n: usize) {
assert!(self.remaining() >= n, "insufficient data"); self.offset += n;
}
/// Skip helper that panics if `n` is `None` or not able to fit in `usize`. /// Only use this for tests because we panic rather than reporting a result. #[cfg(any(test, feature = "test-fixture"))] fn skip_inner(&mutself, n: Option<u64>) { #[expect(clippy::unwrap_used, reason = "Only used in tests.")] self.skip(usize::try_from(n.expect("invalid length")).unwrap());
}
/// Skip a vector. Panics if there isn't enough space. /// Only use this for tests because we panic rather than reporting a result. #[cfg(any(test, feature = "test-fixture"))] pubfn skip_vec(&mutself, n: usize) { let len = self.decode_n(n); self.skip_inner(len);
}
/// Skip a variable length vector. Panics if there isn't enough space. /// Only use this for tests because we panic rather than reporting a result. #[cfg(any(test, feature = "test-fixture"))] pubfn skip_vvec(&mutself) { let len = self.decode_varint(); self.skip_inner(len);
}
/// Skip while the current byte is `predicate`. Returns the number of bytes /// skipped. pubfn skip_while(&mutself, predicate: u8) -> usize { let until = self
.as_ref() // remaining bytes
.iter()
.position(|v| *v != predicate)
.unwrap_or_else(|| self.remaining()); self.skip(until);
until
}
/// Provides the next byte without moving the read position. #[must_use] pubconstfn peek_byte(&self) -> Option<u8> { ifself.remaining() < 1 {
None
} else {
Some(self.buf[self.offset])
}
}
/// Decodes arbitrary data. pubfn decode(&mutself, n: usize) -> Option<&'a [u8]> { ifself.remaining() < n { return None;
} let res = &self.buf[self.offset..self.offset + n]; self.offset += n;
Some(res)
}
pub(crate) fn decode_n(&mutself, n: usize) -> Option<u64> {
debug_assert!(n > 0 && n <= 8); ifself.remaining() < n { return None;
}
Some(if n == 1 { let v = u64::from(self.buf[self.offset]); self.offset += 1;
v
} else { letmut buf = [0; 8];
buf[8 - n..].copy_from_slice(&self.buf[self.offset..self.offset + n]); self.offset += n;
u64::from_be_bytes(buf)
})
}
/// Decodes a big-endian, unsigned integer value into the target type. /// This returns `None` if there is not enough data remaining /// or if the conversion to the identified type fails. /// Conversion is via `u64`, so failures are impossible for /// unsigned integer types: `u8`, `u16`, `u32`, or `u64`. /// Signed types will fail if the high bit is set. pubfn decode_uint<T: TryFrom<u64>>(&mutself) -> Option<T> { let v = self.decode_n(size_of::<T>());
T::try_from(v?).ok()
}
/// Decodes the rest of the buffer. Infallible. pubfn decode_remainder(&mutself) -> &'a [u8] { let res = &self.buf[self.offset..]; self.offset = self.buf.len();
res
}
fn decode_checked(&mutself, n: Option<u64>) -> Option<&'a [u8]> { iflet Ok(l) = usize::try_from(n?) { self.decode(l)
} else { // sizeof(usize) < sizeof(u64) and the value is greater than // usize can hold. Throw away the rest of the input. self.offset = self.buf.len();
None
}
}
/// Decodes a TLS-style length-prefixed buffer. pubfn decode_vec(&mutself, n: usize) -> Option<&'a [u8]> { let len = self.decode_n(n); self.decode_checked(len)
}
/// Decodes a QUIC varint-length-prefixed buffer. pubfn decode_vvec(&mutself) -> Option<&'a [u8]> { let len = self.decode_varint(); self.decode_checked(len)
}
}
// Implement `AsRef` for `Decoder` so that values can be examined without // moving the cursor. impl<'a> AsRef<[u8]> for Decoder<'a> { fn as_ref(&self) -> &'a [u8] {
&self.buf[self.offset..]
}
}
/// Encoder is good for building data structures. pubstruct Encoder<B = Vec<u8>> {
buf: B, /// Tracks the starting position of the buffer when the [`Encoder`] is created. /// This allows distinguishing between bytes that existed in the buffer before /// encoding began and those written by the [`Encoder`] itself.
start: usize,
}
impl<B: Buffer> Encoder<B> { /// Get the length of the [`Encoder`]. /// /// Note that the length of the underlying buffer might be larger. #[must_use] pubfn len(&self) -> usize { self.buf.position() - self.start
}
/// Returns true if the encoder buffer contains no elements. #[must_use] pubfn is_empty(&self) -> bool { self.len() == 0
}
/// Create a view of the current contents of the buffer. /// Note: for a view of a slice, use `Decoder::new(&enc[s..e])` #[must_use] pubfn as_decoder(&self) -> Decoder<'_> {
Decoder::new(self.as_ref())
}
/// Generic encode routine for arbitrary data. /// /// # Panics /// /// When writing to the underlying buffer fails. pubfn encode<D: AsRef<[u8]>>(&mutself, data: D) -> &mutSelf { self.buf
.write_all(data.as_ref())
.expect("Buffer has enough capacity."); self
}
/// Encode a single byte. /// /// # Panics /// /// When writing to the underlying buffer fails. pubfn encode_byte(&mutself, data: u8) -> &mutSelf { self.buf
.write_all(&[data])
.expect("Buffer has enough capacity."); self
}
/// Encode an integer of any size up to u64. /// /// # Panics /// /// When `n` is outside the range `1..=8`. pubfn encode_uint<T: Into<u64>>(&mutself, n: usize, v: T) -> &='color:red'>mutSelf { let v = v.into();
assert!(n > 0 && n <= 8); // Using to_be_bytes() generates better assembly, especially for odd sizes // where it uses rev + strh instead of multiple strb instructions let bytes = v.to_be_bytes(); self.encode(&bytes[8 - n..])
}
/// Encode a QUIC varint. /// /// # Panics /// /// When `v >= 1<<62`. pubfn encode_varint<T: Into<u64>>(&mutself, v: T) -> &mutSelf { let v = v.into(); // Using to_be_bytes() generates better assembly with rev instructions // instead of multiple shifts and ors #[expect(clippy::cast_possible_truncation, reason = "This is intentional.")] match () {
() if v < (1 << 6) => self.encode_byte(v as u8),
() if v < (1 << 14) => self.encode((v as u16 | (1 << 14)).to_be_bytes()),
() if v < (1 << 30) => self.encode((v as u32 | (2 << 30)).to_be_bytes()),
() if v < (1 << 62) => self.encode((v | (3 << 62)).to_be_bytes()),
() => panic!("Varint value too large"),
}
}
/// Encode a vector in TLS style. /// /// # Panics /// /// When `v` is longer than 2^n. pubfn encode_vec(&mutself, n: usize, v: &[u8]) -> &mutSelf { self.encode_uint(
n,
u64::try_from(v.as_ref().len()).expect("v is longer than 2^64"),
)
.encode(v)
}
/// Encode a vector in TLS style using a closure for the contents. /// /// # Panics /// /// When `f()` returns a length larger than `2^8n`. #[expect(
clippy::cast_possible_truncation,
reason = "AND'ing with 0xff makes this OK."
)] pubfn encode_vec_with<F: FnOnce(&mutSelf)>(&mutself, n: usize, f: F) -> &mutSelf { let start = self.buf.position(); self.pad_to(n, 0);
f(self); let len = self.buf.position() - start - n;
assert!(len < (1 << (n * 8))); for i in0..n { self.buf
.write_at(start + i, ((len >> (8 * (n - i - 1))) & 0xff) as u8);
} self
}
/// Encode a vector with a varint length. /// /// # Panics /// /// When `v` is longer than 2^62. pubfn encode_vvec(&mutself, v: &[u8]) -> &mutSelf { self.encode_varint(u64::try_from(v.as_ref().len()).expect("v is longer than 2^64"))
.encode(v)
}
/// Encode a vector with a varint length using a closure. /// /// # Panics /// /// When `f()` writes more than 2^62 bytes. pubfn encode_vvec_with<F: FnOnce(&mutSelf)>(&mutself, f: F) -> &mutSelf { let start = self.buf.position(); // Optimize for short buffers, reserve a single byte for the length. self.buf
.write_all(&[0])
.expect("Buffer has enough capacity.");
f(self); let len = self.buf.position() - start - 1;
// Now to insert a varint for `len` before the encoded block. // // We now have one zero byte at `start`, followed by `len` encoded bytes: // | 0 | ... encoded ... | // We are going to encode a varint by putting the low bytes in that spare byte. // Any additional bytes for the varint are put after the encoded blob: // | low | ... encoded ... | varint high | // Then we will rotate that entire piece right, by however many bytes we add: // | varint high | low | ... encoded ... | // As long as encoding more than 63 bytes is rare, this won't cost much relative // to the convenience of being able to use this function.
let v = u64::try_from(len).expect("encoded value fits in a u64"); // The lower order byte fits before the inserted block of bytes. self.buf.write_at(start, (v & 0xff) as u8); let (count, bits) = match () { // Great. The byte we have is enough.
() if v < (1 << 6) => returnself,
() if v < (1 << 14) => (1, 1 << 6),
() if v < (1 << 30) => (3, 2 << 22),
() if v < (1 << 62) => (7, 3 << 54),
() => panic!("Varint value too large"),
}; // Now, we need to encode the high bits after the main block, ... self.encode_uint(count, (v >> 8) | bits); // ..., then rotate the entire thing right by the same amount. self.buf.rotate_right(start, count); self
}
/// Truncate the encoder to the given size. pubfn truncate(&mutself, len: usize) { self.buf.truncate(len + self.start);
}
/// Pad the [`Encoder`] to `len` with bytes set to `v`. pubfn pad_to(&mutself, len: usize, v: u8) { let buffer_len = self.start + len; if buffer_len > self.buf.position() { self.buf.pad_to(buffer_len, v);
}
}
}
impl Encoder<Vec<u8>> { /// 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. pubfn skip(&mutself, n: usize) {
assert!(n <= self.len(), "Cannot skip beyond buffer length"); self.start += n;
}
/// Static helper function for previewing the results of encoding without doing it. /// /// # Panics /// /// When `v` is too large. #[must_use] pubconstfn varint_len(v: u64) -> usize { match () {
() if v < (1 << 6) => 1,
() if v < (1 << 14) => 2,
() if v < (1 << 30) => 4,
() if v < (1 << 62) => 8,
() => panic!("Varint value too large"),
}
}
/// Static helper to determine how long a varint-prefixed array encodes to. /// /// # Panics /// /// When `len` doesn't fit in a `u64`. #[must_use] pubfn vvec_len(len: usize) -> usize { Self::varint_len(u64::try_from(len).expect("usize should fit into u64")) + len
}
/// Construction of a buffer with a predetermined capacity. #[must_use] pubfn with_capacity(capacity: usize) -> Self { Self {
buf: Vec::with_capacity(capacity),
start: 0,
}
}
/// Don't use this except in testing. /// /// # Panics /// /// When `s` contains non-hex values or an odd number of values. #[cfg(any(test, feature = "test-fixture"))] #[must_use] pubfn from_hex<A: AsRef<str>>(s: A) -> Self { let s = s.as_ref();
assert_eq!(s.len() % 2, 0, "Needs to be even length");
let cap = s.len() / 2; letmut enc = Self::with_capacity(cap);
for i in0..cap { #[expect(clippy::unwrap_used, reason = "Only used in tests.")] let v = u8::from_str_radix(&s[i * 2..i * 2 + 2], 16).unwrap();
enc.encode_byte(v);
}
enc
}
}
#[expect(
clippy::unwrap_in_result,
reason = "successful writing to buffer needs to be guaranteed by caller"
)] impl<B: io::Write> Write for Encoder<B> { fn write_str(&mutself, s: &str) -> fmt::Result { self.buf
.write_all(s.as_bytes())
.expect("Buffer has enough capacity.");
Ok(())
}
}
#[expect(clippy::unnecessary_safety_doc, reason = "relevant for created object")] impl<'a> Encoder<Cursor<&'a mut [u8]>> { /// # Safety /// /// Any mutable method on [`Encoder<Cursor<&mut [u8]>>`] assumes the /// underlying buffer has enough capacity for the called operation. This /// invariant needs to be upheld by the caller. #[must_use] pubconstfn new_borrowed_slice(buf: &'a mut [u8]) -> Self {
Encoder {
buf: Cursor::new(buf),
start: 0,
}
}
}
/// Extends a memory buffer with methods beyond [`std::io::Write`]. Needed for /// [`Encoder`]. /// /// Note that each method operates on the bytes written, not the entire buffer. /// E.g. [`Buffer::as_slice`] returns the bytes written, not all bytes of the /// underlying buffer. pubtrait Buffer: io::Write { fn position(&self) -> usize;
#[test] fn decode_byte_short() { let enc = Encoder::from_hex(""); letmut dec = enc.as_decoder();
assert!(dec.decode_uint::<u8>().is_none());
}
#[test] fn decode_remainder() { let enc = Encoder::from_hex("012345"); letmut dec = enc.as_decoder();
assert_eq!(dec.decode_remainder(), &[0x01, 0x23, 0x45]);
assert!(dec.decode(2).is_none());
letmut dec = Decoder::from(&[]);
assert!(dec.decode_remainder().is_empty());
}
#[test] fn decode_vec() { let enc = Encoder::from_hex("012345"); letmut dec = enc.as_decoder();
assert_eq!(dec.decode_vec(1).expect("read one octet length"), &[0x23]);
assert_eq!(dec.remaining(), 1);
let enc = Encoder::from_hex("00012345"); letmut dec = enc.as_decoder();
assert_eq!(dec.decode_vec(2).expect("read two octet length"), &[0x23]);
assert_eq!(dec.remaining(), 1);
}
#[test] fn decode_vec_short() { // The length is too short. let enc = Encoder::from_hex("02"); letmut dec = enc.as_decoder();
assert!(dec.decode_vec(2).is_none());
// The body is too short. let enc = Encoder::from_hex("0200"); letmut dec = enc.as_decoder();
assert!(dec.decode_vec(1).is_none());
}
#[test] fn decode_vvec() { let enc = Encoder::from_hex("012345"); letmut dec = enc.as_decoder();
assert_eq!(dec.decode_vvec().expect("read one octet length"), &[0x23]);
assert_eq!(dec.remaining(), 1);
let enc = Encoder::from_hex("40012345"); letmut dec = enc.as_decoder();
assert_eq!(dec.decode_vvec().expect("read two octet length"), &[0x23]);
assert_eq!(dec.remaining(), 1);
}
#[test] fn decode_vvec_short() { // The length field is too short. let enc = Encoder::from_hex("ff"); letmut dec = enc.as_decoder();
assert!(dec.decode_vvec().is_none());
let enc = Encoder::from_hex("405500"); letmut dec = enc.as_decoder();
assert!(dec.decode_vvec().is_none());
}
#[test] fn skip() { let enc = Encoder::from_hex("ffff"); letmut dec = enc.as_decoder();
dec.skip(1);
assert_eq!(dec.remaining(), 1);
}
#[test] #[should_panic(expected = "insufficient data")] fn skip_too_much() { let enc = Encoder::from_hex("ff"); letmut dec = enc.as_decoder();
dec.skip(2);
}
#[test] fn skip_vec() { let enc = Encoder::from_hex("012345"); letmut dec = enc.as_decoder();
dec.skip_vec(1);
assert_eq!(dec.remaining(), 1);
}
#[test] #[should_panic(expected = "insufficient data")] fn skip_vec_too_much() { let enc = Encoder::from_hex("ff1234"); letmut dec = enc.as_decoder();
dec.skip_vec(1);
}
#[test] #[should_panic(expected = "invalid length")] fn skip_vec_short_length() { let enc = Encoder::from_hex("ff"); letmut dec = enc.as_decoder();
dec.skip_vec(4);
} #[test] fn skip_vvec() { let enc = Encoder::from_hex("012345"); letmut dec = enc.as_decoder();
dec.skip_vvec();
assert_eq!(dec.remaining(), 1);
}
#[test] #[should_panic(expected = "insufficient data")] fn skip_vvec_too_much() { let enc = Encoder::from_hex("0f1234"); letmut dec = enc.as_decoder();
dec.skip_vvec();
}
#[test] #[should_panic(expected = "invalid length")] fn skip_vvec_short_length() { let enc = Encoder::from_hex("ff"); letmut dec = enc.as_decoder();
dec.skip_vvec();
}
#[test] fn skip_while() { let enc = Encoder::from_hex("000001020202"); letmut dec = enc.as_decoder();
// Skip all zeros let skipped = dec.skip_while(0);
assert_eq!(skipped, 2);
assert_eq!(dec.offset(), 2);
assert_eq!(dec.remaining(), 4);
assert_eq!(dec.as_ref(), &[0x01, 0x02, 0x02, 0x02]);
// Skip until 0x02 let skipped = dec.skip_while(0x01);
assert_eq!(skipped, 1);
assert_eq!(dec.offset(), 3);
assert_eq!(dec.remaining(), 3);
assert_eq!(dec.as_ref(), &[0x02, 0x02, 0x02]);
// Don't skip on no match. let skipped = dec.skip_while(0xFF);
assert_eq!(skipped, 0);
assert_eq!(dec.offset(), 3);
assert_eq!(dec.remaining(), 3);
assert_eq!(dec.as_ref(), &[0x02, 0x02, 0x02]);
// Skip till end. let skipped = dec.skip_while(0x02);
assert_eq!(skipped, 3);
assert_eq!(dec.offset(), 6);
assert_eq!(dec.remaining(), 0);
assert_eq!(dec.as_ref(), &[0u8; 0]);
}
#[test] #[cfg(target_pointer_width = "64")] // Test does not compile on 32-bit targets. #[should_panic(expected = "Varint value too large")] fn encoded_vvec_length_oob() {
_ = Encoder::vvec_len(1 << 62);
}
letmut dec = encoded.as_decoder(); let v = dec.decode_varint().expect("should decode");
assert_eq!(dec.remaining(), 0);
assert_eq!(v, c.v);
}
}
#[test] fn varint_decode_long_zero() { for c in &["4000", "80000000", "c000000000000000"] { let encoded = Encoder::from_hex(c); letmut dec = encoded.as_decoder(); let v = dec.decode_varint().expect("should decode");
assert_eq!(dec.remaining(), 0);
assert_eq!(v, 0);
}
}
#[test] fn varint_decode_short() { for c in &["40", "800000", "c0000000000000"] { let encoded = Encoder::from_hex(c); letmut dec = encoded.as_decoder();
assert!(dec.decode_varint().is_none());
}
}
#[test] fn encode_vvec_with_30bit() { letmut enc = Encoder::default();
enc.encode_vvec_with(|enc_inner| {
enc_inner.encode([0xbe; 16384]); // Just past 14-bit limit
}); let v: Vec<u8> = enc.into(); // 4-byte varint: 0x80004000 for 16384
assert_eq!(&v[..5], &[0x80, 0x00, 0x40, 0x00, 0xbe]);
}
// Test that Deref to &[u8] works for Encoder. #[test] fn encode_builder() { letmut enc = Encoder::from_hex("ff"); let enc2 = Encoder::from_hex("010234");
enc.encode(enc2.as_ref());
assert_eq!(enc, Encoder::from_hex("ff010234"));
}
// Test that Deref to &[u8] works for Decoder. #[test] fn encode_view() { letmut enc = Encoder::from_hex("ff"); let enc2 = Encoder::from_hex("010234"); let v = enc2.as_decoder();
enc.encode(v.as_ref());
assert_eq!(enc, Encoder::from_hex("ff010234"));
}
/// When reusing one [`Buffer`] across [`Encoder`]s, [`Buffer::position`] /// can be larger than [`Encoder::len`]. #[test] fn buffer_vs_encoder_len() { letmut non_empty_vec = vec![1, 2, 3, 4];
assert_eq!(non_empty_vec.len(), Buffer::position(&non_empty_vec));
/// [`Buffer::position`] returns the number of bytes written to and not the /// length of the underyling buffer. /// /// When using [`Vec<u8>`] length and position are equal. When using /// [`Cursor<&mut [u8]>`] they are not. #[test] fn buffer_position() { letmut a = [0; 16]; let buf = Cursor::new(&mut a[..]);
assert_eq!(Buffer::position(&buf), 0);
}
/// [`Encoder::as_decoder`] should only expose the bytes actively encoded through this /// [`Encoder`], not all bytes of the underlying [`Buffer`]. #[test] fn as_decoder_exposes_encoded_bytes_only_not_whole_buffer() { letmut buffer = vec![1, 2, 3, 4]; letmut enc = Encoder::new_borrowed_vec(&mut buffer);
enc.encode([5, 6, 7]);
/// Converting an [`Encoder`] to [`Vec<u8>`] should respect the `start` offset. #[test] fn into_vec_respects_skip() { letmut enc = Encoder::from_hex("010203040506");
enc.skip(2); let v: Vec<u8> = enc.into();
assert_eq!(v, vec![0x03, 0x04, 0x05, 0x06]);
}
/// Converting an [`Encoder`] without skip should return the full buffer. #[test] fn into_vec_without_skip() { let enc = Encoder::from_hex("010203"); let v: Vec<u8> = enc.into();
assert_eq!(v, vec![0x01, 0x02, 0x03]);
}
// 64 bytes exceeds the 6-bit varint range, so the length requires a 2-byte varint. #[test] fn encode_vvec_with_64_bytes() { let v = encode_vvec_n_bytes(64);
assert_eq!(&v[..2], &[0x40, 0x40]); // 64 → 2-byte varint 0x4040
assert_eq!(v.len(), 66);
}
// 16383 is the last value fitting in a 2-byte varint (0x3FFF). #[test] fn encode_vvec_with_16383_bytes() { let v = encode_vvec_n_bytes(16383);
assert_eq!(&v[..2], &[0x7f, 0xff]); // 16383 = 0x3FFF → 2-byte varint 0x7FFF
assert_eq!(v.len(), 16385);
}
// Encoder::truncate when skip (start) is non-zero. #[test] fn truncate_with_skip() { letmut enc = Encoder::from_hex("0102030405");
enc.skip(2);
enc.truncate(1); // Should keep 1 visible byte (index 2 = 0x03).
assert_eq!(enc.as_ref(), &[0x03]);
}
// Encoder::pad_to when already at the target length (should be a no-op). #[test] fn pad_to_no_op() { letmut enc = Encoder::from_hex("010203");
enc.pad_to(3, 0xff);
assert_eq!(enc.as_ref(), &[0x01, 0x02, 0x03]); // Unchanged.
}
// with_capacity should not be equivalent to Default (capacity is preserved). #[test] fn with_capacity_has_capacity() { let enc = Encoder::with_capacity(64);
assert_eq!(enc.len(), 0); // Can't directly inspect capacity, but round-trip works. let v: Vec<u8> = enc.into();
assert!(v.capacity() >= 64);
}
// From<Encoder> for Vec<u8> with start == 0 (no drain path). #[test] fn into_vec_no_skip() { let enc = Encoder::from_hex("0102"); let v: Vec<u8> = enc.into();
assert_eq!(v, &[0x01, 0x02]);
}
// Cursor<&mut [u8]> truncate at exactly the current position (no-op branch). #[test] fn cursor_truncate_no_op() { letmut buf = [0u8; 8]; letmut cur = Cursor::new(&mut buf[..]);
cur.write_all(&[1, 2, 3]).unwrap();
assert_eq!(Buffer::position(&cur), 3);
cur.truncate(3); // At current position — should be a no-op.
assert_eq!(Buffer::position(&cur), 3);
assert_eq!(cur.as_slice(), &[1, 2, 3]);
}
// Cursor<&mut [u8]> write_at should modify the byte at the given index. #[test] fn cursor_write_at() { letmut buf = [0u8; 8]; letmut cur = Cursor::new(&mut buf[..]);
cur.write_all(&[1, 2, 3]).unwrap();
cur.write_at(1, 0xab);
assert_eq!(cur.as_slice(), &[1, 0xab, 3]);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.