Repository navigation
refactor: introduce SamTag newtype for two-character BAM tag fields - #241
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #241 +/- ##
==========================================
+ Coverage 89.04% 89.29% +0.24%
==========================================
Files 114 118 +4
Lines 55304 57201 +1897
==========================================
+ Hits 49247 51079 +1832
- Misses 6057 6122 +65 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
@coderabbitai review |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 8 minutes and 30 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (33)
📝 WalkthroughWalkthroughA new 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 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.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/commands/group.rs (1)
992-994: Consider using SamTag for RX and MI tags as well.Lines 992 and 994 still use raw byte arrays (
*b"RX"and*b"MI"), while line 993 uses the newSamTag::CB. Per PR objectives,SamTagprovides constants for bothRXandMI. Using them consistently would improve type safety and readability.♻️ Proposed refactor for consistency
- let raw_tag: [u8; 2] = *b"RX"; + let raw_tag: [u8; 2] = *SamTag::RX; let cell_tag = Tag::from(SamTag::CB); - let assign_tag_bytes: [u8; 2] = *b"MI"; + let assign_tag_bytes: [u8; 2] = *SamTag::MI;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/commands/group.rs` around lines 992 - 994, Replace the raw byte arrays for RX and MI with SamTag-based Tags for consistency: instead of let raw_tag: [u8; 2] = *b"RX" and let assign_tag_bytes: [u8; 2] = *b"MI", construct Tag values using Tag::from(SamTag::RX) and Tag::from(SamTag::MI) (similar to how cell_tag uses Tag::from(SamTag::CB)); update the variable types if necessary to hold a Tag rather than a [u8;2].src/commands/review.rs (1)
686-686: Inconsistent MI tag construction.Lines 627 and 835 use
Tag::from(SamTag::MI), but lines 686 and 795 still use raw byte formTag::from([b'M', b'I']). For consistency with the PR objective, consider updating these as well.♻️ Proposed fix
- let mi_tag = noodles::sam::alignment::record::data::field::Tag::from([b'M', b'I']); + let mi_tag = noodles::sam::alignment::record::data::field::Tag::from(SamTag::MI);Apply at both line 686 and line 795.
Also applies to: 795-795
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/commands/review.rs` at line 686, The mi_tag is constructed inconsistently: replace the raw byte construction using noodles::sam::alignment::record::data::field::Tag::from([b'M', b'I']) with the canonical Tag::from(SamTag::MI) to match other usages; update both occurrences where mi_tag is defined so they use SamTag::MI (ensure you import or reference SamTag accordingly and keep the variable name mi_tag and the same surrounding logic).src/commands/extract.rs (1)
763-764: Optional consistency improvement. These local byte literals could useSamTagconstants (e.g.,&*SamTag::RX) for self-documentation, aligning with the PR's typed-tag goal. Low priority.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/commands/extract.rs` around lines 763 - 764, Replace the hard-coded byte literals assigned to umi_tag and cell_tag with the typed SamTag constants to improve self-documentation: use the existing SamTag constants (e.g., SamTag::RX and SamTag::CB) and take a byte-slice reference compatible with the current signature (for example by using &*SamTag::RX and &*SamTag::CB) when initializing umi_tag and cell_tag so the variables remain of type &[u8; 2] while aligning with the PR’s typed-tag approach.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/fgumi-sam/src/tag.rs`:
- Around line 50-58: The public const constructor SamTag::new currently accepts
any bytes and can be used to create invalid SamTag values; update it to validate
both bytes are printable ASCII (0x20..=0x7E) by adding a const-compatible
assertion that checks a and b are each within that range and includes a
descriptive message, so invalid inputs fail at compile time in const contexts
and panic at runtime otherwise while keeping the function const, pub, and
#[must_use].
---
Nitpick comments:
In `@src/commands/extract.rs`:
- Around line 763-764: Replace the hard-coded byte literals assigned to umi_tag
and cell_tag with the typed SamTag constants to improve self-documentation: use
the existing SamTag constants (e.g., SamTag::RX and SamTag::CB) and take a
byte-slice reference compatible with the current signature (for example by using
&*SamTag::RX and &*SamTag::CB) when initializing umi_tag and cell_tag so the
variables remain of type &[u8; 2] while aligning with the PR’s typed-tag
approach.
In `@src/commands/group.rs`:
- Around line 992-994: Replace the raw byte arrays for RX and MI with
SamTag-based Tags for consistency: instead of let raw_tag: [u8; 2] = *b"RX" and
let assign_tag_bytes: [u8; 2] = *b"MI", construct Tag values using
Tag::from(SamTag::RX) and Tag::from(SamTag::MI) (similar to how cell_tag uses
Tag::from(SamTag::CB)); update the variable types if necessary to hold a Tag
rather than a [u8;2].
In `@src/commands/review.rs`:
- Line 686: The mi_tag is constructed inconsistently: replace the raw byte
construction using
noodles::sam::alignment::record::data::field::Tag::from([b'M', b'I']) with the
canonical Tag::from(SamTag::MI) to match other usages; update both occurrences
where mi_tag is defined so they use SamTag::MI (ensure you import or reference
SamTag accordingly and keep the variable name mi_tag and the same surrounding
logic).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ab9a1feb-7828-4236-809e-b9ebb72023db
📒 Files selected for processing (15)
crates/fgumi-sam/src/lib.rscrates/fgumi-sam/src/tag.rssrc/commands/codec.rssrc/commands/correct.rssrc/commands/dedup.rssrc/commands/downsample.rssrc/commands/duplex.rssrc/commands/extract.rssrc/commands/group.rssrc/commands/review.rssrc/commands/shared_metrics.rssrc/commands/simplex.rssrc/lib/sam/mod.rssrc/lib/unified_pipeline/bam.rssrc/lib/unified_pipeline/base.rs
e71345e to
c22a11e
Compare
3c30430 to
66ad2d8
Compare
66ad2d8 to
25cd94f
Compare
4d62ccf to
78cd579
Compare
25cd94f to
8c3d7be
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
crates/fgumi-sam/src/builder.rs (1)
600-609: These builders still bypass the new invariant for custom tags.The built-in
RGpath now usesSamTag, but custom attrs still come through raw&strand are converted with a byte-length check only. That means invalid tags are still silently dropped or emitted from arbitrary 2-byte UTF-8, so the public builder API still doesn't guarantee a valid SAM tag. Prefer storingSamTaghere too, or validate viaSamTag::try_frombefore insert.Based on learnings, in the fgumi-sam crate (
crates/fgumi-sam), thebuildermodule is intentionally public API.Also applies to: 654-661, 835-844
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/fgumi-sam/src/builder.rs` around lines 600 - 609, The custom-attribute path currently builds raw two-byte Tags from &str (attrs) which can accept invalid or arbitrary UTF-8; change this to validate/convert the attribute key via SamTag::try_from (or store SamTag in the builder) before inserting: for each (tag_str, value) in self.attrs, call SamTag::try_from(tag_str) and on success convert to Tag (Tag::from(sam_tag)) and insert that, otherwise handle the error/skip accordingly; apply the same change to the other occurrences mentioned (the blocks around first_read.data_mut().insert(...) at the other ranges).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/fgumi-sam/src/tag.rs`:
- Around line 4-6: Update the module docs to stop calling SamTag::new
"infallible" and instead state that SamTag::new will panic on invalid bytes;
keep the distinction that std::str::FromStr is the fallible (non-panicking)
constructor used by clap for CLI parsing. Reference SamTag::new and
std::str::FromStr in the doc text so readers know which constructor panics and
which returns a Result.
- Around line 60-65: The SamTag constructor currently allows any printable
ASCII; tighten validation in SamTag::new (and the other tag constructor at the
same file, e.g., the second const constructor around lines 171-175) to enforce
the SAM spec: require the first byte to satisfy is_ascii_alphabetic() and the
second to satisfy is_ascii_alphanumeric(); replace the existing
is_ascii_graphic() checks with a.is_ascii_alphabetic() &&
b.is_ascii_alphanumeric(), and apply the same check in the other constructor so
invalid tags like "A!" or "1A" are rejected.
In `@src/lib/commands/extract.rs`:
- Around line 531-536: The current guard only rejects RX but needs to reject all
reserved/always-appended tags (e.g., RG, RX, CB, CY, BC, QT, QX) and re-apply
the SAM aux-tag syntax validation that was lost; update the check around
self.single_tag in extract.rs to validate that the provided tag is not one of
the reserved tags (RX, RG, CB, CY, BC, QT, QX) and also validate the aux-tag
syntax (the same rules SamTag previously enforced beyond ASCII) — either by
calling a new SamTag::is_valid_aux_tag(s) helper or by expanding
SamTag::from_str to return a clear error for bad aux-tag syntax and using that
here; ensure the ensure! message mentions which reserved tag was rejected and
includes the invalid tag string for debugging.
---
Nitpick comments:
In `@crates/fgumi-sam/src/builder.rs`:
- Around line 600-609: The custom-attribute path currently builds raw two-byte
Tags from &str (attrs) which can accept invalid or arbitrary UTF-8; change this
to validate/convert the attribute key via SamTag::try_from (or store SamTag in
the builder) before inserting: for each (tag_str, value) in self.attrs, call
SamTag::try_from(tag_str) and on success convert to Tag (Tag::from(sam_tag)) and
insert that, otherwise handle the error/skip accordingly; apply the same change
to the other occurrences mentioned (the blocks around
first_read.data_mut().insert(...) at the other ranges).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e665b9a3-71f9-4599-b6f5-16e08c388bf0
📒 Files selected for processing (33)
crates/fgumi-consensus/src/duplex_caller.rscrates/fgumi-sam/src/builder.rscrates/fgumi-sam/src/lib.rscrates/fgumi-sam/src/tag.rssrc/lib/commands/codec.rssrc/lib/commands/compare/bams.rssrc/lib/commands/compare/raw_compare.rssrc/lib/commands/correct.rssrc/lib/commands/dedup.rssrc/lib/commands/downsample.rssrc/lib/commands/duplex.rssrc/lib/commands/extract.rssrc/lib/commands/group.rssrc/lib/commands/review.rssrc/lib/commands/shared_metrics.rssrc/lib/commands/simplex.rssrc/lib/commands/simulate/correct_reads.rssrc/lib/commands/sort.rssrc/lib/commands/zipper.rssrc/lib/grouper.rssrc/lib/mi_group.rssrc/lib/read_info.rssrc/lib/sam/mod.rssrc/lib/sort/keys.rssrc/lib/sort/raw.rssrc/lib/template.rssrc/lib/unified_pipeline/bam.rssrc/lib/unified_pipeline/base.rstests/integration/test_bgzf_eof.rstests/integration/test_downsample_command.rstests/integration/test_duplex_command.rstests/integration/test_simplex_command.rstests/integration/test_streaming_input.rs
✅ Files skipped from review due to trivial changes (13)
- src/lib/commands/sort.rs
- src/lib/commands/duplex.rs
- tests/integration/test_bgzf_eof.rs
- tests/integration/test_duplex_command.rs
- src/lib/commands/codec.rs
- src/lib/sam/mod.rs
- src/lib/unified_pipeline/base.rs
- src/lib/commands/compare/bams.rs
- src/lib/commands/review.rs
- src/lib/commands/dedup.rs
- crates/fgumi-consensus/src/duplex_caller.rs
- src/lib/mi_group.rs
- src/lib/commands/downsample.rs
🚧 Files skipped from review as they are similar to previous changes (1)
- src/lib/unified_pipeline/bam.rs
8c3d7be to
97d8835
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/lib/commands/extract.rs (1)
531-542: Keep the emitted-tag set in one place.
RESERVED_OUTPUT_TAGSand the two write paths now spell out the same tag set separately. The next tag addition can update one site and miss validation or the other output path.♻️ Refactor direction
const EXTRACT_EMITTED_TAGS: &[SamTag] = &[ SamTag::RX, SamTag::QX, SamTag::CB, SamTag::CY, SamTag::BC, SamTag::QT, SamTag::RG, ];Use that constant for the guard, and move the actual tag appends into a small shared helper used by both
make_raw_recordsandmake_raw_records_static.Also applies to: 812-843, 1149-1180
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/commands/extract.rs` around lines 531 - 542, Create a single shared constant (e.g., EXTRACT_EMITTED_TAGS: &[SamTag]) containing the tags currently duplicated in RESERVED_OUTPUT_TAGS, then replace the local RESERVED_OUTPUT_TAGS usage in the guard with that constant; next factor the logic that appends those emitted tags out of make_raw_records and make_raw_records_static into a small shared helper (e.g., append_extract_emitted_tags or build_emitted_tags) and call it from both make_raw_records and make_raw_records_static so both validation (the ensure! guard) and the actual output paths reference the same canonical tag set (update references to RESERVED_OUTPUT_TAGS accordingly).src/lib/commands/duplex.rs (1)
548-548: Consider removing remaining rawb"CB"literals for one source of truth.You now derive
TagfromSamTag::CB, but raw grouper paths still hardcode*b"CB". Reusing a shared derived byte pair would prevent drift.Suggested cleanup
- let cell_tag = Tag::from(SamTag::CB); + let cell_tag = Tag::from(SamTag::CB); + let cell_tag_bytes: [u8; 2] = *SamTag::CB.as_ref(); @@ - .with_cell_tag(Some(*b"CB")); + .with_cell_tag(Some(cell_tag_bytes)); @@ - .with_cell_tag(Some(*b"CB")), + .with_cell_tag(Some(cell_tag_bytes)),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/commands/duplex.rs` at line 548, You introduced cell_tag via let cell_tag = Tag::from(SamTag::CB); but there are still raw b"CB" literals in grouper path code; locate usages of the raw byte pair b"CB" (e.g., in grouper path construction or pattern matches) and replace them with the shared derived value (use cell_tag or Tag::from(SamTag::CB).as_ref() / .to_vec() as appropriate) so all code reads the same source of truth (Tag / SamTag::CB) and avoids drifting hardcoded byte literals.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/fgumi-sam/src/tag.rs`:
- Around line 3-7: The doc comment overstates the allowed characters—SamTag
actually enforces that both bytes are ASCII alphabetic characters (A–Z, a–z)
rather than any printable ASCII—so update the rustdoc around the SamTag type
(and the similar text at lines 44–46) to say it wraps [u8; 2] and represents two
ASCII alphabetic characters, and mention use of SamTag::new (const, panics on
invalid bytes) and std::str::FromStr (fallible) for runtime parsing; ensure the
description explicitly lists the exact invariant (two ASCII letters) so it
matches the FromStr/new validation logic.
---
Nitpick comments:
In `@src/lib/commands/duplex.rs`:
- Line 548: You introduced cell_tag via let cell_tag = Tag::from(SamTag::CB);
but there are still raw b"CB" literals in grouper path code; locate usages of
the raw byte pair b"CB" (e.g., in grouper path construction or pattern matches)
and replace them with the shared derived value (use cell_tag or
Tag::from(SamTag::CB).as_ref() / .to_vec() as appropriate) so all code reads the
same source of truth (Tag / SamTag::CB) and avoids drifting hardcoded byte
literals.
In `@src/lib/commands/extract.rs`:
- Around line 531-542: Create a single shared constant (e.g.,
EXTRACT_EMITTED_TAGS: &[SamTag]) containing the tags currently duplicated in
RESERVED_OUTPUT_TAGS, then replace the local RESERVED_OUTPUT_TAGS usage in the
guard with that constant; next factor the logic that appends those emitted tags
out of make_raw_records and make_raw_records_static into a small shared helper
(e.g., append_extract_emitted_tags or build_emitted_tags) and call it from both
make_raw_records and make_raw_records_static so both validation (the ensure!
guard) and the actual output paths reference the same canonical tag set (update
references to RESERVED_OUTPUT_TAGS accordingly).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0c2ce0eb-6cbd-436f-9922-41e447800ca1
📒 Files selected for processing (33)
crates/fgumi-consensus/src/duplex_caller.rscrates/fgumi-sam/src/builder.rscrates/fgumi-sam/src/lib.rscrates/fgumi-sam/src/tag.rssrc/lib/commands/codec.rssrc/lib/commands/compare/bams.rssrc/lib/commands/compare/raw_compare.rssrc/lib/commands/correct.rssrc/lib/commands/dedup.rssrc/lib/commands/downsample.rssrc/lib/commands/duplex.rssrc/lib/commands/extract.rssrc/lib/commands/group.rssrc/lib/commands/review.rssrc/lib/commands/shared_metrics.rssrc/lib/commands/simplex.rssrc/lib/commands/simulate/correct_reads.rssrc/lib/commands/sort.rssrc/lib/commands/zipper.rssrc/lib/grouper.rssrc/lib/mi_group.rssrc/lib/read_info.rssrc/lib/sam/mod.rssrc/lib/sort/keys.rssrc/lib/sort/raw.rssrc/lib/template.rssrc/lib/unified_pipeline/bam.rssrc/lib/unified_pipeline/base.rstests/integration/test_bgzf_eof.rstests/integration/test_downsample_command.rstests/integration/test_duplex_command.rstests/integration/test_simplex_command.rstests/integration/test_streaming_input.rs
✅ Files skipped from review due to trivial changes (19)
- src/lib/sam/mod.rs
- src/lib/commands/sort.rs
- src/lib/read_info.rs
- src/lib/commands/downsample.rs
- tests/integration/test_duplex_command.rs
- tests/integration/test_simplex_command.rs
- src/lib/commands/compare/bams.rs
- src/lib/commands/shared_metrics.rs
- tests/integration/test_streaming_input.rs
- crates/fgumi-sam/src/builder.rs
- src/lib/commands/codec.rs
- src/lib/unified_pipeline/base.rs
- src/lib/sort/keys.rs
- src/lib/sort/raw.rs
- src/lib/commands/simplex.rs
- src/lib/commands/compare/raw_compare.rs
- src/lib/commands/dedup.rs
- tests/integration/test_downsample_command.rs
- src/lib/commands/group.rs
🚧 Files skipped from review as they are similar to previous changes (5)
- src/lib/commands/simulate/correct_reads.rs
- src/lib/grouper.rs
- src/lib/commands/review.rs
- src/lib/template.rs
- src/lib/unified_pipeline/bam.rs
97d8835 to
7216ed1
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/lib/commands/duplex.rs (1)
298-299: Complete CB tag migration in grouping calls.Line 298 and Line 548 use
SamTag::CB, but Line 415 and Line 596 still use*b"CB". Prefer one source of truth.Suggested diff
- .with_cell_tag(Some(*b"CB")); + .with_cell_tag(Some(*SamTag::CB));- .with_cell_tag(Some(*b"CB")), + .with_cell_tag(Some(*SamTag::CB)),Also applies to: 548-549
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/commands/duplex.rs` around lines 298 - 299, Multiple places mix raw byte literal tags (`*b"CB"`) with the new enum-based tag (`SamTag::CB`)—standardize to the enum-based Tag by replacing all uses of `*b"CB"` in grouping/packing calls with `Tag::from(SamTag::CB)` (e.g., where you set `cell_tag` and in any grouping invocations around the same logic) so there is a single source of truth; search for `*b"CB"` and update those call sites to use `Tag::from(SamTag::CB)` to match the existing `cell_tag` usage.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/lib/commands/duplex.rs`:
- Around line 298-299: Multiple places mix raw byte literal tags (`*b"CB"`) with
the new enum-based tag (`SamTag::CB`)—standardize to the enum-based Tag by
replacing all uses of `*b"CB"` in grouping/packing calls with
`Tag::from(SamTag::CB)` (e.g., where you set `cell_tag` and in any grouping
invocations around the same logic) so there is a single source of truth; search
for `*b"CB"` and update those call sites to use `Tag::from(SamTag::CB)` to match
the existing `cell_tag` usage.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5b701b40-98f7-44bd-aaaf-f2f29d3792ad
📒 Files selected for processing (33)
crates/fgumi-consensus/src/duplex_caller.rscrates/fgumi-sam/src/builder.rscrates/fgumi-sam/src/lib.rscrates/fgumi-sam/src/tag.rssrc/lib/commands/codec.rssrc/lib/commands/compare/bams.rssrc/lib/commands/compare/raw_compare.rssrc/lib/commands/correct.rssrc/lib/commands/dedup.rssrc/lib/commands/downsample.rssrc/lib/commands/duplex.rssrc/lib/commands/extract.rssrc/lib/commands/group.rssrc/lib/commands/review.rssrc/lib/commands/shared_metrics.rssrc/lib/commands/simplex.rssrc/lib/commands/simulate/correct_reads.rssrc/lib/commands/sort.rssrc/lib/commands/zipper.rssrc/lib/grouper.rssrc/lib/mi_group.rssrc/lib/read_info.rssrc/lib/sam/mod.rssrc/lib/sort/keys.rssrc/lib/sort/raw.rssrc/lib/template.rssrc/lib/unified_pipeline/bam.rssrc/lib/unified_pipeline/base.rstests/integration/test_bgzf_eof.rstests/integration/test_downsample_command.rstests/integration/test_duplex_command.rstests/integration/test_simplex_command.rstests/integration/test_streaming_input.rs
✅ Files skipped from review due to trivial changes (14)
- tests/integration/test_streaming_input.rs
- tests/integration/test_simplex_command.rs
- src/lib/commands/compare/bams.rs
- src/lib/commands/simplex.rs
- src/lib/commands/sort.rs
- src/lib/commands/codec.rs
- src/lib/unified_pipeline/base.rs
- crates/fgumi-consensus/src/duplex_caller.rs
- src/lib/sort/keys.rs
- tests/integration/test_bgzf_eof.rs
- src/lib/commands/group.rs
- src/lib/commands/correct.rs
- src/lib/template.rs
- src/lib/read_info.rs
🚧 Files skipped from review as they are similar to previous changes (9)
- src/lib/sam/mod.rs
- src/lib/grouper.rs
- src/lib/commands/downsample.rs
- src/lib/commands/compare/raw_compare.rs
- crates/fgumi-sam/src/builder.rs
- src/lib/commands/review.rs
- src/lib/commands/dedup.rs
- src/lib/unified_pipeline/bam.rs
- src/lib/commands/shared_metrics.rs
Add a `SamTag` newtype in `fgumi-sam` that wraps `[u8; 2]` and validates printable-ASCII at construction. Provides named constants for SAM-spec tags (RX, QX, MI, CB, CY, BC, QT, OX, BZ, RG, NM, MQ, MC, MS, AS, XS, PG, XT) and the fgumi-internal `pa` tag, plus a `const fn to_noodles_tag()` helper for use in `const` contexts. `SamTag` implements `FromStr` for clap parsing, `Deref<Target=[u8; 2]>` for use with byte-slice APIs, and `From<SamTag> for Tag` for noodles interop. Sweep production code and tests to replace ad-hoc `Tag::new(b'X', b'Y')`, `Tag::from([b'X', b'Y'])`, and `b"XX"` literal tag patterns with the named constants. `extract`'s `single_tag` and `clipping_attribute` CLI fields are typed as `Option<SamTag>` so clap performs the validation. Closes #193.
7216ed1 to
c0b258b
Compare
zipper previously hard-coded stdin to the SAM text reader. When callers
piped BAM bytes (e.g. `bwameth.py | samtools view -b | fgumi zipper`,
common in nf-core / Galaxy pipelines), the SAM parser misread BGZF
binary and crashed with a confusing
Error: invalid flags
Caused by: lexical parse error: 'the string to parse was empty'
This extends the BAM detection from #183 (file inputs) to stdin: peek
the first four bytes via a `BufReader`, and if they match the BGZF
magic `\x1f\x8b\x08\x04`, route to a single-threaded BGZF + BAM reader
rather than the SAM reader. SAM-on-stdin (the fast aligner streaming
path) is unchanged.
A new `MappedReader::StdinBam` variant carries the
`bam::io::Reader<bgzf::io::Reader<BufReader<Box<dyn Read + Send>>>>`
into the reader thread. Single-threaded BGZF is used because stdin is
non-seekable; the existing `BamReaderAuto` requires `Seek` for the
multi-threaded variant.
The same "BAM input detected" warning #183 emits for file inputs now
fires for stdin BAM, nudging users toward the SAM-text fast path.
Adds `test_zipper_bam_stdin_input` integration test that reproduces
the production failure mode (BAM bytes on stdin with
`--restore-unconverted-bases`) and asserts tag-transfer success.
Drive-by: migrate the four remaining `Tag::from([..])` sites in
`test_zipper_command.rs` to the SamTag newtype style introduced in
#241 and already used by the other integration test files.
zipper previously hard-coded stdin to the SAM text reader. When callers
piped BAM bytes (e.g. `bwameth.py | samtools view -b | fgumi zipper`,
common in nf-core / Galaxy pipelines), the SAM parser misread BGZF
binary and crashed with a confusing
Error: invalid flags
Caused by: lexical parse error: 'the string to parse was empty'
This extends the BAM detection from #183 (file inputs) to stdin: peek
the first four bytes via a `BufReader`, and if they match the BGZF
magic `\x1f\x8b\x08\x04`, route to a single-threaded BGZF + BAM reader
rather than the SAM reader. SAM-on-stdin (the fast aligner streaming
path) is unchanged.
A new `MappedReader::StdinBam` variant carries the
`bam::io::Reader<bgzf::io::Reader<BufReader<Box<dyn Read + Send>>>>`
into the reader thread. Single-threaded BGZF is used because stdin is
non-seekable; the existing `BamReaderAuto` requires `Seek` for the
multi-threaded variant.
The same "BAM input detected" warning #183 emits for file inputs now
fires for stdin BAM, nudging users toward the SAM-text fast path.
Adds `test_zipper_bam_stdin_input` integration test that reproduces
the production failure mode (BAM bytes on stdin with
`--restore-unconverted-bases`) and asserts tag-transfer success.
Drive-by: migrate the four remaining `Tag::from([..])` sites in
`test_zipper_command.rs` to the SamTag newtype style introduced in
#241 and already used by the other integration test files.
zipper previously hard-coded stdin to the SAM text reader. When callers
piped BAM bytes (e.g. `bwameth.py | samtools view -b | fgumi zipper`,
common in nf-core / Galaxy pipelines), the SAM parser misread BGZF
binary and crashed with a confusing
Error: invalid flags
Caused by: lexical parse error: 'the string to parse was empty'
This extends the BAM detection from #183 (file inputs) to stdin: peek
the first four bytes via a `BufReader`, and if they match the BGZF
magic `\x1f\x8b\x08\x04`, route to a single-threaded BGZF + BAM reader
rather than the SAM reader. SAM-on-stdin (the fast aligner streaming
path) is unchanged.
A new `MappedReader::StdinBam` variant carries the
`bam::io::Reader<bgzf::io::Reader<BufReader<Box<dyn Read + Send>>>>`
into the reader thread. Single-threaded BGZF is used because stdin is
non-seekable; the existing `BamReaderAuto` requires `Seek` for the
multi-threaded variant.
The same "BAM input detected" warning #183 emits for file inputs now
fires for stdin BAM, nudging users toward the SAM-text fast path.
Adds `test_zipper_bam_stdin_input` integration test that reproduces
the production failure mode (BAM bytes on stdin with
`--restore-unconverted-bases`) and asserts tag-transfer success.
Drive-by: migrate the four remaining `Tag::from([..])` sites in
`test_zipper_command.rs` to the SamTag newtype style introduced in
#241 and already used by the other integration test files.
zipper previously hard-coded stdin to the SAM text reader. When callers
piped BAM bytes (e.g. `bwameth.py | samtools view -b | fgumi zipper`,
common in nf-core / Galaxy pipelines), the SAM parser misread BGZF
binary and crashed with a confusing
Error: invalid flags
Caused by: lexical parse error: 'the string to parse was empty'
This extends the BAM detection from #183 (file inputs) to stdin: peek
the first four bytes via a `BufReader`, and if they match the BGZF
magic `\x1f\x8b\x08\x04`, route to a single-threaded BGZF + BAM reader
rather than the SAM reader. SAM-on-stdin (the fast aligner streaming
path) is unchanged.
A new `MappedReader::StdinBam` variant carries the
`bam::io::Reader<bgzf::io::Reader<BufReader<Box<dyn Read + Send>>>>`
into the reader thread. Single-threaded BGZF is used because stdin is
non-seekable; the existing `BamReaderAuto` requires `Seek` for the
multi-threaded variant.
The same "BAM input detected" warning #183 emits for file inputs now
fires for stdin BAM, nudging users toward the SAM-text fast path.
Adds `test_zipper_bam_stdin_input` integration test that reproduces
the production failure mode (BAM bytes on stdin with
`--restore-unconverted-bases`) and asserts tag-transfer success.
Drive-by: migrate the four remaining `Tag::from([..])` sites in
`test_zipper_command.rs` to the SamTag newtype style introduced in
#241 and already used by the other integration test files.
Stacked on #240.
Closes #193
Summary
SamTag([u8; 2])tocrates/fgumi-samwith named constants for all standard SAM spec tags used by fgumi (RX,QX,MI,CB,CY,BC,QT,OX,BZ,RG) and the fgumi-internalPAtagSamTagimplementsFromStr/TryFrom<&str>(validates length and ASCII),Display,Deref<Target=[u8;2]>,AsRef<[u8;2]>,From<SamTag> for noodles::Tag, andPartialEq<[u8;2]>extract:single_tagandclipping_attributechange fromOption<String>toOption<SamTag>— clap now validates tag format automatically viaFromStr, eliminating the manualensure!length checks andString → [u8;2]conversionsTag::new(b'C', b'B')/Tag::new(b'M', b'I')/Tag::new(b'R', b'X')call sites in command files replaced withTag::from(SamTag::CB/MI/RX)unified_pipeline/bam.rsandbase.rsdefault cell tag construction usesSamTag::CBdownsample.rslocalMI_TAGconstant replaced byTag::from(SamTag::MI)inlineTest plan
cargo ci-test— 2289 tests passcargo ci-fmt— cleancargo ci-lint— clean--single-tag ABCis rejected by clap before execution--single-tag ZUis accepted and used correctly