Skip to main content

Crate darkbio_cobs

Crate darkbio_cobs 

Source
Expand description

§Fast COBS encoder and decoder

License: BSD-3-Clause

This crate is a fast implementation of Consistent Overhead Byte Stuffing (COBS). It doesn’t do much, but it does it fast. Although there might be eventual fixups and feature expansions for streaming codecs, assume the library is “done”.

The library is no_std and never allocates. Disabling the default std feature only costs runtime SIMD detection on x86_64, where memchr then picks SSE2 instead of AVX2.

§Usage

The codec works on caller provided buffers and returns how many bytes it wrote. The two sizing helpers compute the worst case output for an input length, so a buffer of that size always fits.

use darkbio_cobs::{decode, decode_buffer, encode, encode_buffer};

let data = [0x11, 0x00, 0x22, 0x33, 0x00];

let mut encoded = vec![0u8; encode_buffer(data.len())];
let len = encode(&data, &mut encoded).unwrap();
assert_eq!(&encoded[..len], &[0x02, 0x11, 0x03, 0x22, 0x33, 0x01]);

let mut decoded = vec![0u8; decode_buffer(len)];
let len = decode(&encoded[..len], &mut decoded).unwrap();
assert_eq!(&decoded[..len], &data);

An encoding never contains a zero byte, so a framing layer can delimit packets with zeros and hand each frame to the decoder. Frames from such a layer contain no zeros by construction, which lets decode_nonzero skip the validation scan. Feeding it a zero anyway yields an error or garbage output, never memory unsafety.

use darkbio_cobs::{decode_buffer, decode_nonzero};

let frame = [0x02, 0x11, 0x03, 0x22, 0x33, 0x01];

let mut decoded = vec![0u8; decode_buffer(frame.len())];
let len = decode_nonzero(&frame, &mut decoded).unwrap();
assert_eq!(&decoded[..len], &[0x11, 0x00, 0x22, 0x33, 0x00]);

Malformed input is reported through DecodeError, naming the offending position. Both directions refuse an undersized output buffer with a BufferTooSmall error before writing anything.

use darkbio_cobs::{decode, DecodeError};

let mut decoded = [0u8; 16];
let error = DecodeError::ChunkOverflow { at: 0, marker: 3, len: 2 };
assert_eq!(decode(&[0x03, 0x41], &mut decoded), Err(error));

The encode_unchecked, decode_unchecked and decode_nonzero_unchecked variants skip the buffer size checks and keep only a debug assertion, so they are unsafe to call. The caller must size the buffers with the helpers, anything smaller is undefined behavior in release builds.

use darkbio_cobs::{encode_buffer, encode_unchecked};

let data = [0x11, 0x00, 0x22];

let mut encoded = vec![0u8; encode_buffer(data.len())];
let len = unsafe { encode_unchecked(&data, &mut encoded) };
assert_eq!(&encoded[..len], &[0x02, 0x11, 0x02, 0x22]);

§Performance

You can run the benchmarks to see the performance of the checked versions, unchecked versions and the currently most popular Rust cobs package (v0.5.1).

% cargo bench -- --quiet

This crate, measured on an Apple M2 Max with rustc 1.98.0 in a release build.

16 B256 B4 KiB64 KiB256 KiB1 MiB4 MiB
encode3.1 GiB/s28.9 GiB/s20.4 GiB/s21.5 GiB/s19.4 GiB/s10.6 GiB/s8.5 GiB/s
encode_unchecked3.1 GiB/s28.9 GiB/s25.9 GiB/s20.3 GiB/s19.0 GiB/s11.9 GiB/s8.7 GiB/s
decode2.7 GiB/s14.2 GiB/s24.9 GiB/s21.4 GiB/s17.9 GiB/s18.0 GiB/s17.8 GiB/s
decode_unchecked2.7 GiB/s20.9 GiB/s25.6 GiB/s20.3 GiB/s17.8 GiB/s18.1 GiB/s17.9 GiB/s
decode_nonzero4.6 GiB/s31.2 GiB/s34.4 GiB/s25.7 GiB/s22.7 GiB/s22.7 GiB/s22.3 GiB/s
decode_nonzero_unchecked5.0 GiB/s57.9 GiB/s35.0 GiB/s26.4 GiB/s22.8 GiB/s22.2 GiB/s22.6 GiB/s

The reference cobs crate at 0.5.1 on the same machine.

16 B256 B4 KiB64 KiB256 KiB1 MiB4 MiB
encode1.5 GiB/s1.5 GiB/s1.5 GiB/s1.6 GiB/s1.6 GiB/s1.6 GiB/s1.6 GiB/s
decode1.0 GiB/s1.1 GiB/s1.1 GiB/s1.1 GiB/s1.1 GiB/s1.1 GiB/s1.1 GiB/s

§License

This library is licensed under the BSD 3-Clause License.

Enums§

DecodeError
Error types that can be returned from decoding.
EncodeError
Error types that can be returned from encoding.

Functions§

decode
Decodes an opaque data blob with COBS using 0 as the sentinel value. Returns the number of bytes the decoding took. Returns an error if the output buffer is too small or if the input is malformed.
decode_buffer
Computes the maximum size needed to COBS decode a blind input data.
decode_nonzero
Decodes an opaque data blob with COBS using 0 as the sentinel value, assuming the input contains no zero bytes, a guarantee usually provided by a zero delimited framing layer. Skipping the validation scan makes this faster than decode, but violating the assumption yields either a decode error or garbage output, never memory unsafety. Returns the number of bytes the decoding took. Returns an error if the output buffer is too small or if the input is malformed.
decode_nonzero_unchecked⚠
Decodes an opaque data blob with COBS using 0 as the sentinel value, assuming the input contains no zero bytes. Returns the number of bytes the decoding took.
decode_unchecked⚠
Decodes an opaque data blob with COBS using 0 as the sentinel value. Returns the number of bytes the decoding took.
encode
Encodes an opaque data blob with COBS using 0 as the sentinel value. Returns the number of bytes the encoding took. Returns an error if the output buffer is too small.
encode_buffer
Computes the maximum size needed to COBS encode a blind input blob.
encode_unchecked⚠
Encodes an opaque data blob with COBS using 0 as the sentinel value. Returns the number of bytes the encoding took.