Skip to content

Read content-stream operands through ArrayContext instead of Operands - #585

Merged
Velli20 merged 1 commit into
mainfrom
remove-operands
Oct 20, 2026
Merged

Velli20 merged 1 commit into
mainfrom
remove-operands

Conversation

@Velli20

@Velli20 Velli20 commented Oct 18, 2026

Copy link
Copy Markdown
Owner

Summary

Removes the Operands type from pdf-content-stream-operators. Operators now decode their operands with the existing pdf-object-reader decoders, reading in place from the parser's reused operand buffer.

  • PdfOperator::read takes &mut OperandContext (an ArrayContext over a ReadSession) and returns ReadResult.
    • Matrices are Self::new(operands.read_array()?), numbers operands.at(i)?, and names/strings operands.at::<PdfString>(i)?.bytes, which shares the parsed bytes.
    • TJ uses the Vec<PdfTextItem> decoder and sc/SC use read_all.
  • The parser keeps one Vec<ObjectVariant> per stream and passes it as ArrayContext::new(&operands, session). No per-operator Vec, Arc or byte copies.

pdf-object-reader changes that make this faster than before

  • ReadSession::read decodes direct values in place instead of copying each one into a new PdfObject (Arc) and cloning the traversal state. Following references moved into read_reference.
  • ObjectContext borrows &ObjectVariant, so context.object().value() becomes context.object() across the decoder crates.
  • ObjectVariant::kind() and ObjectVariant::dictionary() now hold the logic; PdfObject and ResolvedObject delegate to them.
  • ArrayContext borrows any slice (new ArrayContext::new) and gains read_array::<T, N>(). read_all presizes its Vec.
  • Adds #[inline] on the small hot decoders. The release profile (opt-level = "z", fat LTO), which benches inherit, barely inlines without it.

Benchmark

crates/pdf-content-stream/benches/operator_parsing.rs, release profile. Each of 5 interleaved rounds ran a git archive export of main and this branch back to back.

group main this branch change faster in
dispatch_heavy 493.7 µs 461.8 µs −6.5% 5/5
mixed 2316 µs 2235 µs −3.5% 5/5
numeric_heavy 1302 µs 1255 µs −3.6% 5/5

Test plan

  • cargo fmt --check
  • cargo clippy --all --workspace
  • cargo test --workspace --exclude pdf-graphics-skia --exclude pdf-conformance: 1,110 passed. Skia crates not built locally; CI covers them.

🤖 Generated with Claude Code

Operators now decode their operands with the pdf-object-reader decoders,
reading in place from the parser's reused operand buffer through
ArrayContext::new, so the Operands type and its parallel accessors are gone.

To keep this path faster than before, ReadSession::read decodes direct
values without copying them into a PdfObject or cloning the traversal
state, and ObjectContext borrows the value. ArrayContext gains read_array
for fixed numeric runs, and read_all presizes its vector.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Velli20
Velli20 merged commit 1d8cccb into main Oct 20, 2026
10 checks passed
@Velli20
Velli20 deleted the remove-operands branch October 20, 2026 15:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant