fix: stream points instead of buffering the whole cloud in memory#1
Conversation
The las Writer clears the header it receives and recomputes point counts, per-return counts, and bounds itself on write/close, so the manual header.add_point pass was dead work and the Vec buffer only existed to support it. Stream read->write in one pass for constant memory usage. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
WalkthroughThe LAS point-processing logic in src/main.rs is refactored from a buffered approach that rebuilt the header and collected all points into a vector, to a streaming approach that clones the reader header, creates a writer directly, and writes points one at a time as they are read. ChangesStreaming LAS Processing
Estimated code review effort: 1 (Trivial) | ~5 minutes Sequence Diagram(s)sequenceDiagram
participant Main
participant Reader
participant Writer
Main->>Reader: clone header
Main->>Writer: create writer from header
loop for each point in reader.points()
Reader-->>Main: Ok(point) or Err
alt Ok(point)
Main->>Writer: write point
else Err
Main->>Main: skip point
end
end
Main->>Writer: close writer
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/main.rs (1)
22-27: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winConsider logging skipped invalid points.
Invalid points are silently dropped via
Err(_) => continue, matching the prior behavior, but with no visibility into how many/which points were skipped. For multi-GB files this could mask a systemic read issue (e.g., truncated file, corrupt VLR) without any trace in the output.♻️ Optional: surface a warning per skipped point
- Err(_) => continue, + Err(e) => { + eprintln!("Warning: skipping invalid point: {e}"); + continue; + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main.rs` around lines 22 - 27, The point-processing loop in main currently drops reader.points() errors silently via Err(_) => continue, so add visibility for skipped invalid points while keeping the same behavior. Update the match in the reader.points() iteration to log a warning or otherwise record each skipped point, referencing the point-processing logic in main and the writer.write path so it’s easy to locate even if lines move. If you want to avoid noisy output, at minimum count skipped points and emit a summary warning after the loop.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/main.rs`:
- Around line 22-27: The point-processing loop in main currently drops
reader.points() errors silently via Err(_) => continue, so add visibility for
skipped invalid points while keeping the same behavior. Update the match in the
reader.points() iteration to log a warning or otherwise record each skipped
point, referencing the point-processing logic in main and the writer.write path
so it’s easy to locate even if lines move. If you want to avoid noisy output, at
minimum count skipped points and emit a summary warning after the loop.
Thermo-nuclear code quality reviewVerdict: approves the bar. No major findings. This is the rare PR where the diff itself is the code-judo move. The old Structural checklist against the bar:
One deliberate non-finding: Merge-order notes (overlap with sibling PRs — intentionally not pulled into this diff):
Approved. This is what a fix PR should look like: smaller, simpler, and more correct than what it replaced. |
Problem
main()buffered the entire point cloud into aVec<las::Point>while manually callingheader.add_point(&point)on a header round-tripped throughlas::Builder, then wrote the buffered points in a second pass. LAS files are routinely multi-GB, so buffering the whole cloud in memory is a real OOM risk.Why the manual header pass was dead work
Verified against the
las0.8.8 crate source:Writer::newcallsheader.clear()on the header you pass it, zeroing point counts, per-return counts, and bounds — so everything the manualadd_pointloop accumulated was discarded before the first point was written.writer.write(point)internally callsheader.add_pointitself.writer.close()seeks back and rewrites the finished header with the recomputed counts and bounds.The
Builder::from(header).into_header()round-trip and theVecbuffer existed solely to support that dead pass.Change
Rewrite
main()as a single streaming read -> write pass: clone the reader's header, hand it toWriter::from_path, and write each point as it is read. Memory usage is now constant regardless of file size, and the unusedBuilderimport is removed (theRead/Writetraits stay — they providepoints()/write()).Output is behaviorally equivalent: the writer produces the same recomputed header (counts, per-return counts, bounds) and the same point stream; invalid points are still silently skipped.
cargo buildandcargo clippypass with no warnings.🤖 Generated with Claude Code
Summary by CodeRabbit