Issue #701: std performance: Bytes::find is a byte loop, range indexes are not inlined, Bytes::from(Vec) copies

Open and answer this issue on GitHub.

compiler, ready · opened 2026-10-19 · updated 2026-10-19 · 1 comment

Found while writing a hand-optimised 1BRC program. Each is confirmed in the source on develop 0.0.1065.

Bytes::find is a position loop

crates/nikaia-std/src/bytes.rs:104, ByteReads for [u8], does rest.iter().position(|b| *b == byte), and neither find is #[inline]. In the 1BRC program a row’s two finds cost 50-78 instructions a row. The specification promises otherwise:

Range indexes are not inlined

b[i..<i + 8] lowers to index::at(i..i + 8). impl At for Range<$t> (index.rs:68, also RangeFrom and RangeInclusive) and Span::at (range.rs:167) have no #[inline], while the scalar At for $t has #[inline(always)]. In the 1BRC program Span::at stayed a call: 10.2 instructions a row.

Bytes::from(Vec[u8]) copies

bytes.rs:143-147 builds buffer: Arc::from(bytes) with buffer: Arc<[u8]>, which allocates and copies. fs::read followed by Bytes::from therefore copies the whole file twice.

To build

  1. Bytes::find (both impls) uses memchr (already a dependency through winnow) or a SWAR scan, and is #[inline]. Test: the existing find tests, plus a needle at every offset 0..64 in a 64-byte buffer.
  2. #[inline] on the At impls for ranges and on Span::at. Check with benches/brc/brc.sh that nothing grows.
  3. Bytes::from(Vec[u8]) takes the allocation without a copy, e.g. a Bytes backed by Arc<Vec<u8>> or bytes::Bytes-style ownership. Keep Bytes cheap to clone and slice. Test: the pointer of the buffer is unchanged after from.

Comments

keywan-ghadami, 2026-10-19

Part 3 (Bytes::from(Vec) without a copy) is decided and absorbed by #718: ADR-373 D2 — Bytes(v) takes a Vec[u8] over and copies nothing, and fs::read makes its Bytes that way. The commit that finishes #718 will name this issue too.


Generated by Claude Code

Back to Open Issues