From b6650f972c9f8cece5f69733933a5a05d4e5d4b5 Mon Sep 17 00:00:00 2001 From: Michael Macias Date: Thu, 8 Feb 2024 15:06:46 -0600 Subject: [PATCH] Update to noodles 0.63.0 --- Cargo.lock | 41 ++++++--- Cargo.toml | 5 +- src/cli.rs | 10 +- src/commands/quantify.rs | 2 +- src/count.rs | 55 ++++++----- src/count/filter.rs | 20 ++-- src/detect.rs | 16 ++-- src/lib.rs | 3 +- src/match_intervals.rs | 47 +++++++--- src/record.rs | 2 +- src/record_pairs.rs | 106 ++++++++++------------ src/record_pairs/segment_position.rs | 6 +- tests/quantify_single_end_forward_test.rs | 2 +- 13 files changed, 176 insertions(+), 139 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 37f91f7..7bfc4d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,6 +74,16 @@ version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +[[package]] +name = "bstr" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "byteorder" version = "1.5.0" @@ -387,9 +397,9 @@ dependencies = [ [[package]] name = "noodles" -version = "0.59.0" +version = "0.63.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "254ff100d92851724c8b271d6dccd3f21bb7be8438413995d67dcca3f996f2ac" +checksum = "a2212020b3faa067f38e4b5ecd558ff85a84f05d772882590d79cb772dadbbd1" dependencies = [ "noodles-bam", "noodles-bgzf", @@ -400,11 +410,12 @@ dependencies = [ [[package]] name = "noodles-bam" -version = "0.51.0" +version = "0.55.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaf0ae212f452acbb416e01057cbee99ce63a6219728cc3656a5bbb331ebb04" +checksum = "3980bc5cf6294d2ec132f8572d57b52f190e788ecd74a71b86ab81e6ce73afbb" dependencies = [ "bit-vec", + "bstr", "byteorder", "bytes", "indexmap", @@ -416,9 +427,9 @@ dependencies = [ [[package]] name = "noodles-bgzf" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d578e5a173cbfac77295db4188c959966ce24a3364e009d363170d1ed44066a" +checksum = "8970db2e84adb1007377dd3988258d7a64e3fc4c05602ebf94e1f8cba207c030" dependencies = [ "byteorder", "bytes", @@ -429,15 +440,15 @@ dependencies = [ [[package]] name = "noodles-core" -version = "0.12.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fbe3192fe33acacabaedd387657f39b0fc606f1996d546db0dfe14703b843a" +checksum = "7336c3be652de4e05444c9b12a32331beb5ba3316e8872d92bfdd8ef3b06c282" [[package]] name = "noodles-csi" -version = "0.28.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "912aaef460c3ccf466f79f681ed866c7e70b78da7af88c4bbb082a6a64971ebd" +checksum = "a60dfe0919f7ecbd081a82eb1d32e8f89f9041932d035fe8309073c8c01277bf" dependencies = [ "bit-vec", "byteorder", @@ -448,9 +459,9 @@ dependencies = [ [[package]] name = "noodles-gff" -version = "0.25.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fec62bd9306cce6d551c9c7075beca940aec283efd18648b6d04860b693fd092" +checksum = "14f8ec87fe3630f57d6d8ea24cbc2cbd0bfed1fe66238bda7a7c3fb6a36d3713" dependencies = [ "indexmap", "noodles-bgzf", @@ -461,11 +472,12 @@ dependencies = [ [[package]] name = "noodles-sam" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0287fb408d26b656cde1862379a96763791bf730943693bdea57081074c7dc01" +checksum = "17b778d5136a0d7659e2e1950df586e0fe18ec793bf44e8a4123417af39ba062" dependencies = [ "bitflags", + "bstr", "indexmap", "lexical-core", "memchr", @@ -578,6 +590,7 @@ name = "squab" version = "0.1.0" dependencies = [ "anyhow", + "bstr", "clap", "crossbeam-channel", "flate2", diff --git a/Cargo.toml b/Cargo.toml index a3bf36d..dcc3f3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,14 +13,15 @@ codegen-units = 1 [dependencies] anyhow = "1.0.32" +bstr = { version = "1.9.0", default-features = false, features = ["std"] } clap = { version = "4.0.10", features = ["derive", "string"] } crossbeam-channel = "0.5.6" flate2 = "1.0.14" git-testament = "0.2.0" interval-tree = { git = "https://github.com/zaeleus/interval-tree.git", rev = "e303d7254d53de5c418d6079d4b66c30c10958d4" } mimalloc = { version = "0.1.26", default-features = false } -noodles = { version = "0.59.0", features = ["bam", "bgzf", "core", "gff", "sam"] } -noodles-bgzf = { version = "0.25.0", features = ["libdeflate"] } +noodles = { version = "0.63.0", features = ["bam", "bgzf", "core", "gff", "sam"] } +noodles-bgzf = { version = "0.26.0", features = ["libdeflate"] } thiserror = "1.0.40" tracing = "0.1.25" tracing-subscriber = "0.3.3" diff --git a/src/cli.rs b/src/cli.rs index cdc8353..5f3f14f 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -2,7 +2,7 @@ use std::{num::NonZeroUsize, path::PathBuf}; use clap::{Parser, Subcommand}; use git_testament::{git_testament, render_testament}; -use noodles::sam::record::MappingQuality; +use noodles::sam::alignment::record::MappingQuality; use crate::{normalization::Method, StrandSpecificationOption}; @@ -71,7 +71,7 @@ pub struct Quantify { #[arg(short = 'i', long, default_value = "gene_id")] pub id: String, - #[arg(long, default_value = "10")] + #[arg(long, value_parser = parse_mapping_quality, default_value = "10")] pub min_mapping_quality: MappingQuality, /// Output destination for feature counts. @@ -89,3 +89,9 @@ pub struct Quantify { /// Input alignment file. pub src: PathBuf, } + +fn parse_mapping_quality(s: &str) -> Result { + s.parse::() + .map_err(|_| "invalid input") + .and_then(|n| MappingQuality::new(n).ok_or("missing mapping quality")) +} diff --git a/src/commands/quantify.rs b/src/commands/quantify.rs index 326e513..c30680e 100644 --- a/src/commands/quantify.rs +++ b/src/commands/quantify.rs @@ -36,7 +36,7 @@ where let mut reader = bgzf::reader::Builder::default() .set_worker_count(worker_count) .build_from_path(bam_src.as_ref()) - .map(bam::Reader::from) + .map(bam::io::Reader::from) .with_context(|| format!("Could not open {}", bam_src.as_ref().display()))?; let header = reader.read_header()?; diff --git a/src/count.rs b/src/count.rs index d426f7c..d379a03 100644 --- a/src/count.rs +++ b/src/count.rs @@ -12,17 +12,15 @@ use std::{ thread, }; +use bstr::{BStr, ByteSlice}; use interval_tree::IntervalTree; use noodles::{ bam, core::Position, gff, - sam::{ - header::{ - record::value::{map::ReferenceSequence, Map}, - ReferenceSequences, - }, - record::ReferenceSequenceName, + sam::header::{ + record::value::{map::ReferenceSequence, Map}, + ReferenceSequences, }, }; @@ -33,7 +31,7 @@ use self::context::Event; const CHUNK_SIZE: usize = 8192; pub fn count_single_end_records( - mut reader: bam::Reader, + mut reader: bam::io::Reader, features: &Features, reference_sequences: &ReferenceSequences, filter: &Filter, @@ -47,7 +45,7 @@ where let (tx, rx) = crossbeam_channel::bounded(worker_count.get()); scope.spawn(move || { - let mut records = reader.lazy_records(); + let mut records = reader.records(); loop { let mut chunk = Vec::with_capacity(CHUNK_SIZE); @@ -110,7 +108,7 @@ pub fn count_single_end_record( reference_sequences: &ReferenceSequences, filter: &Filter, strand_specification: StrandSpecification, - record: &bam::lazy::Record, + record: &bam::Record, ) -> io::Result { if let Some(event) = filter.filter(record)? { return Ok(event); @@ -119,14 +117,14 @@ pub fn count_single_end_record( let tree = match get_tree( features, reference_sequences, - record.reference_sequence_id()?, + record.reference_sequence_id().transpose()?, )? { Some(t) => t, None => return Ok(Event::NoFeature), }; let cigar = record.cigar(); - let start = record.alignment_start()?.expect("missing alignment start"); + let start = record.alignment_start().expect("missing alignment start")?; let intervals = MatchIntervals::new(&cigar, start); let flags = record.flags(); @@ -141,7 +139,7 @@ pub fn count_single_end_record( } pub fn count_paired_end_records( - reader: bam::Reader, + reader: bam::io::Reader, features: &Features, reference_sequences: &ReferenceSequences, filter: &Filter, @@ -238,20 +236,24 @@ pub fn count_paired_end_record_pair( reference_sequences: &ReferenceSequences, filter: &Filter, strand_specification: StrandSpecification, - r1: &bam::lazy::Record, - r2: &bam::lazy::Record, + r1: &bam::Record, + r2: &bam::Record, ) -> io::Result { if let Some(event) = filter.filter_pair(r1, r2)? { return Ok(event); } - let tree = match get_tree(features, reference_sequences, r1.reference_sequence_id()?)? { + let tree = match get_tree( + features, + reference_sequences, + r1.reference_sequence_id().transpose()?, + )? { Some(t) => t, None => return Ok(Event::NoFeature), }; let cigar = r1.cigar(); - let start = r1.alignment_start()?.expect("missing alignment start"); + let start = r1.alignment_start().expect("missing alignment start")?; let intervals = MatchIntervals::new(&cigar, start); let f1 = r1.flags(); @@ -262,13 +264,17 @@ pub fn count_paired_end_record_pair( let mut set = find(tree, intervals, strand_specification, is_reverse)?; - let tree = match get_tree(features, reference_sequences, r2.reference_sequence_id()?)? { + let tree = match get_tree( + features, + reference_sequences, + r2.reference_sequence_id().transpose()?, + )? { Some(t) => t, None => return Ok(Event::NoFeature), }; let cigar = r2.cigar(); - let start = r2.alignment_start()?.expect("missing alignment start"); + let start = r2.alignment_start().expect("missing alignment start")?; let intervals = MatchIntervals::new(&cigar, start); let f2 = r2.flags(); @@ -289,7 +295,7 @@ pub fn count_paired_end_singleton_record( reference_sequences: &ReferenceSequences, filter: &Filter, strand_specification: StrandSpecification, - record: &bam::lazy::Record, + record: &bam::Record, ) -> io::Result { if let Some(event) = filter.filter(record)? { return Ok(event); @@ -298,14 +304,14 @@ pub fn count_paired_end_singleton_record( let tree = match get_tree( features, reference_sequences, - record.reference_sequence_id()?, + record.reference_sequence_id().transpose()?, )? { Some(t) => t, None => return Ok(Event::NoFeature), }; let cigar = record.cigar(); - let start = record.alignment_start()?.expect("missing alignment start"); + let start = record.alignment_start().expect("missing alignment start")?; let intervals = MatchIntervals::new(&cigar, start); let flags = record.flags(); @@ -361,9 +367,10 @@ fn find( fn get_reference_sequence( reference_sequences: &ReferenceSequences, reference_sequence_id: Option, -) -> io::Result<(&ReferenceSequenceName, &Map)> { +) -> io::Result<(&BStr, &Map)> { reference_sequence_id .and_then(|id| reference_sequences.get_index(id)) + .map(|(name, map)| (name.as_bstr(), map)) .ok_or_else(|| { io::Error::new( io::ErrorKind::InvalidData, @@ -388,7 +395,7 @@ pub fn get_tree<'t>( reference_sequence_id: Option, ) -> io::Result>> { let (name, _) = get_reference_sequence(reference_sequences, reference_sequence_id)?; - Ok(features.get(name.as_str())) + Ok(features.get(name)) } #[cfg(test)] @@ -423,7 +430,7 @@ mod tests { let reference_sequence_id = Some(1); let (name, reference_sequence) = get_reference_sequence(&reference_sequences, reference_sequence_id)?; - assert_eq!(name.as_str(), "sq1"); + assert_eq!(name, &b"sq1"[..]); assert_eq!(usize::from(reference_sequence.length()), 13); let reference_sequence_id = None; diff --git a/src/count/filter.rs b/src/count/filter.rs index 3d5e73a..47bd68f 100644 --- a/src/count/filter.rs +++ b/src/count/filter.rs @@ -2,7 +2,7 @@ use std::io; use noodles::{ bam, - sam::{self, record::MappingQuality}, + sam::{self, alignment::record::MappingQuality}, }; use super::context::Event; @@ -48,7 +48,7 @@ impl Filter { } } - pub fn filter(&self, record: &bam::lazy::Record) -> io::Result> { + pub fn filter(&self, record: &bam::Record) -> io::Result> { let flags = record.flags(); if flags.is_unmapped() { @@ -74,11 +74,7 @@ impl Filter { Ok(None) } - pub fn filter_pair( - &self, - r1: &bam::lazy::Record, - r2: &bam::lazy::Record, - ) -> io::Result> { + pub fn filter_pair(&self, r1: &bam::Record, r2: &bam::Record) -> io::Result> { let f1 = r1.flags(); let f2 = r2.flags(); @@ -113,12 +109,12 @@ impl Filter { } } -fn is_nonunique_record(record: &bam::lazy::Record) -> io::Result { - use sam::record::data::field::{tag, Type}; +fn is_nonunique_record(record: &bam::Record) -> io::Result { + use sam::alignment::record::data::field::{Tag, Type}; let data = record.data(); - let value = match data.get(&tag::ALIGNMENT_HIT_COUNT) { + let value = match data.get(&Tag::ALIGNMENT_HIT_COUNT) { Some(result) => result?, None => return Ok(false), }; @@ -128,8 +124,8 @@ fn is_nonunique_record(record: &bam::lazy::Record) -> io::Result { None => Err(io::Error::new( io::ErrorKind::InvalidData, format!( - "invalid {} value type: expected {:?}, got {:?}", - tag::ALIGNMENT_HIT_COUNT, + "invalid {:?} value type: expected {:?}, got {:?}", + Tag::ALIGNMENT_HIT_COUNT, Type::Int32, value.ty() ), diff --git a/src/detect.rs b/src/detect.rs index 7baf7a4..82e8702 100644 --- a/src/detect.rs +++ b/src/detect.rs @@ -42,8 +42,8 @@ enum Strand { Reverse, } -impl From for Strand { - fn from(flags: sam::record::Flags) -> Self { +impl From for Strand { + fn from(flags: sam::alignment::record::Flags) -> Self { if flags.is_reverse_complemented() { Self::Reverse } else { @@ -67,7 +67,7 @@ impl TryFrom for Strand { fn count_paired_end_record( counts: &mut Counts, tree: &IntervalTree, - flags: sam::record::Flags, + flags: sam::alignment::record::Flags, start: Position, end: Position, ) -> io::Result<()> { @@ -107,7 +107,7 @@ fn count_paired_end_record( fn count_single_end_record( counts: &mut Counts, tree: &IntervalTree, - flags: sam::record::Flags, + flags: sam::alignment::record::Flags, start: Position, end: Position, ) { @@ -144,12 +144,12 @@ where { use crate::record::alignment_end; - let mut reader = File::open(src).map(bam::Reader::new)?; + let mut reader = File::open(src).map(bam::io::Reader::new)?; reader.read_header()?; let mut counts = Counts::default(); - for result in reader.lazy_records().take(MAX_RECORDS) { + for result in reader.records().take(MAX_RECORDS) { let record = result?; let flags = record.flags(); @@ -158,14 +158,14 @@ where continue; } - let reference_sequence_id = record.reference_sequence_id()?; + let reference_sequence_id = record.reference_sequence_id().transpose()?; let tree = match get_tree(features, reference_sequences, reference_sequence_id)? { Some(t) => t, None => continue, }; - let alignment_start = record.alignment_start()?; + let alignment_start = record.alignment_start().transpose()?; let cigar = record.cigar(); let start = alignment_start.expect("missing alignment start"); diff --git a/src/lib.rs b/src/lib.rs index 0a8afd0..576ad94 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,13 +25,14 @@ use std::{ io::{self, BufRead}, }; +use bstr::BString; use interval_tree::IntervalTree; use noodles::core::{self as core, Position}; use thiserror::Error; use tracing::info; pub type Entry = (String, noodles::gff::record::Strand); -pub type Features = HashMap>; +pub type Features = HashMap>; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum StrandSpecification { diff --git a/src/match_intervals.rs b/src/match_intervals.rs index 11bef85..a32996e 100644 --- a/src/match_intervals.rs +++ b/src/match_intervals.rs @@ -1,6 +1,10 @@ use std::{io, ops::RangeInclusive}; -use noodles::{bam::lazy::record::Cigar, core::Position, sam::record::cigar::Op}; +use noodles::{ + bam::record::Cigar, + core::Position, + sam::alignment::record::cigar::{op::Kind, Op}, +}; pub struct MatchIntervals<'a> { ops: Box> + 'a>, @@ -20,8 +24,6 @@ impl<'a> Iterator for MatchIntervals<'a> { type Item = io::Result>; fn next(&mut self) -> Option { - use noodles::sam::record::cigar::op::Kind; - loop { let op = match self.ops.next()? { Ok(op) => op, @@ -59,27 +61,44 @@ impl<'a> Iterator for MatchIntervals<'a> { #[cfg(test)] mod tests { - use noodles::{bam, sam}; + use noodles::{ + bam, + sam::{self, alignment::io::Write}, + }; use super::*; #[test] fn test_next() -> Result<(), Box> { - let record = sam::alignment::Record::builder() + let record = sam::alignment::RecordBuf::builder() .set_alignment_start(Position::MIN) - .set_cigar("1M2I3D4N5S6H7P8=9X".parse()?) + .set_cigar( + [ + Op::new(Kind::Match, 1), + Op::new(Kind::Insertion, 2), + Op::new(Kind::Deletion, 3), + Op::new(Kind::Skip, 4), + Op::new(Kind::SoftClip, 5), + Op::new(Kind::HardClip, 6), + Op::new(Kind::Pad, 7), + Op::new(Kind::SequenceMatch, 8), + Op::new(Kind::SequenceMismatch, 9), + ] + .into_iter() + .collect(), + ) .build(); - let mut writer = bam::Writer::from(Vec::new()); - writer.write_record(&sam::Header::default(), &record)?; - let buf = writer.into_inner()[4..].to_vec(); + let mut writer = bam::io::Writer::from(Vec::new()); + writer.write_alignment_record(&sam::Header::default(), &record)?; + + let mut reader = bam::io::Reader::from(writer.get_ref().as_slice()); - let raw_record = bam::lazy::Record::try_from(buf)?; + let mut record = bam::Record::default(); + reader.read_record(&mut record)?; - let cigar = raw_record.cigar(); - let start = raw_record - .alignment_start()? - .expect("missing alignment start"); + let cigar = record.cigar(); + let start = record.alignment_start().expect("missing alignment start")?; let mut it = MatchIntervals::new(&cigar, start); assert_eq!( diff --git a/src/record.rs b/src/record.rs index a97d8e7..352fee4 100644 --- a/src/record.rs +++ b/src/record.rs @@ -1,6 +1,6 @@ use std::io; -use noodles::{bam::lazy::record::Cigar, core::Position}; +use noodles::{bam::record::Cigar, core::Position}; pub fn alignment_end( alignment_start: Option, diff --git a/src/record_pairs.rs b/src/record_pairs.rs index efb0975..2dd5615 100644 --- a/src/record_pairs.rs +++ b/src/record_pairs.rs @@ -24,8 +24,8 @@ pub struct RecordPairs where R: Read, { - reader: bam::Reader, - buf: HashMap, + reader: bam::io::Reader, + buf: HashMap, primary_only: bool, } @@ -33,7 +33,7 @@ impl RecordPairs where R: Read, { - pub fn new(reader: bam::Reader, primary_only: bool) -> Self { + pub fn new(reader: bam::io::Reader, primary_only: bool) -> Self { Self { reader, buf: HashMap::new(), @@ -41,11 +41,11 @@ where } } - pub fn next_pair(&mut self) -> io::Result> { + pub fn next_pair(&mut self) -> io::Result> { loop { - let mut record = bam::lazy::Record::default(); + let mut record = bam::Record::default(); - if self.reader.read_lazy_record(&mut record)? == 0 { + if self.reader.read_record(&mut record)? == 0 { if !self.buf.is_empty() { warn!("{} records are singletons", self.buf.len()); } @@ -79,44 +79,44 @@ where } } -fn is_not_primary(record: &bam::lazy::Record) -> io::Result { +fn is_not_primary(record: &bam::Record) -> io::Result { let flags = record.flags(); Ok(flags.is_secondary() || flags.is_supplementary()) } -fn key(record: &bam::lazy::Record) -> io::Result { +fn key(record: &bam::Record) -> io::Result { Ok(( - record.read_name().map(|buf| buf.as_ref().to_vec()), + record.name().map(|name| name.as_bytes().to_vec()), SegmentPosition::try_from(record.flags()) .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?, - record.reference_sequence_id()?, - record.alignment_start()?, - record.mate_reference_sequence_id()?, - record.mate_alignment_start()?, + record.reference_sequence_id().transpose()?, + record.alignment_start().transpose()?, + record.mate_reference_sequence_id().transpose()?, + record.mate_alignment_start().transpose()?, record.template_length(), )) } -fn mate_key(record: &bam::lazy::Record) -> io::Result { +fn mate_key(record: &bam::Record) -> io::Result { Ok(( - record.read_name().map(|buf| buf.as_ref().to_vec()), + record.name().map(|name| name.as_bytes().to_vec()), SegmentPosition::try_from(record.flags()) .map(|p| p.mate()) .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?, - record.mate_reference_sequence_id()?, - record.mate_alignment_start()?, - record.reference_sequence_id()?, - record.alignment_start()?, + record.mate_reference_sequence_id().transpose()?, + record.mate_alignment_start().transpose()?, + record.reference_sequence_id().transpose()?, + record.alignment_start().transpose()?, -record.template_length(), )) } pub struct Singletons<'a> { - drain: Drain<'a, RecordKey, bam::lazy::Record>, + drain: Drain<'a, RecordKey, bam::Record>, } impl<'a> Iterator for Singletons<'a> { - type Item = bam::lazy::Record; + type Item = bam::Record; fn next(&mut self) -> Option { self.drain.next().map(|(_, r)| r) @@ -129,22 +129,21 @@ mod tests { use noodles::sam::{ self, + alignment::{io::Write, record::Flags, record_buf::Name}, header::record::value::{map::ReferenceSequence, Map}, - record::{Flags, ReadName}, }; use super::*; - fn build_record_pair( - ) -> Result<(bam::lazy::Record, bam::lazy::Record), Box> { - let read_name: ReadName = "r0".parse()?; + fn build_record_pair() -> Result<(bam::Record, bam::Record), Box> { + let name = Name::from(b"r0"); let reference_sequence_id = 0; let alignment_start = Position::try_from(8)?; let mate_reference_sequence_id = 1; let mate_position = Position::try_from(13)?; - let r1 = sam::alignment::Record::builder() - .set_read_name(read_name.clone()) + let rb1 = sam::alignment::RecordBuf::builder() + .set_name(name.clone()) .set_flags(Flags::SEGMENTED | Flags::FIRST_SEGMENT) .set_reference_sequence_id(reference_sequence_id) .set_alignment_start(alignment_start) @@ -153,8 +152,8 @@ mod tests { .set_template_length(144) .build(); - let r2 = sam::alignment::Record::builder() - .set_read_name(read_name) + let rb2 = sam::alignment::RecordBuf::builder() + .set_name(name) .set_flags(Flags::SEGMENTED | Flags::LAST_SEGMENT) .set_reference_sequence_id(mate_reference_sequence_id) .set_alignment_start(mate_position) @@ -164,28 +163,23 @@ mod tests { .build(); let header = sam::Header::builder() - .add_reference_sequence( - "sq0".parse()?, - Map::::new(NonZeroUsize::MIN), - ) - .add_reference_sequence( - "sq1".parse()?, - Map::::new(NonZeroUsize::MIN), - ) + .add_reference_sequence("sq0", Map::::new(NonZeroUsize::MIN)) + .add_reference_sequence("sq1", Map::::new(NonZeroUsize::MIN)) .build(); - let mut writer = bam::Writer::from(Vec::new()); - writer.write_record(&header, &r1)?; - let buf1 = writer.into_inner()[4..].to_vec(); + let mut writer = bam::io::Writer::from(Vec::new()); + writer.write_alignment_record(&header, &rb1)?; + writer.write_alignment_record(&header, &rb2)?; - let mut writer = bam::Writer::from(Vec::new()); - writer.write_record(&header, &r2)?; - let buf2 = writer.into_inner()[4..].to_vec(); + let mut reader = bam::io::Reader::from(writer.get_ref().as_slice()); - let lr1 = bam::lazy::Record::try_from(buf1)?; - let lr2 = bam::lazy::Record::try_from(buf2)?; + let mut r1 = bam::Record::default(); + reader.read_record(&mut r1)?; - Ok((lr1, lr2)) + let mut r2 = bam::Record::default(); + reader.read_record(&mut r2)?; + + Ok((r1, r2)) } #[test] @@ -194,12 +188,12 @@ mod tests { let actual = key(&r1)?; let expected = ( - r1.read_name().map(|buf| buf.as_ref().to_vec()), + r1.name().map(|name| name.as_bytes().to_vec()), SegmentPosition::First, - r1.reference_sequence_id()?, - r1.alignment_start()?, - r1.mate_reference_sequence_id()?, - r1.mate_alignment_start()?, + r1.reference_sequence_id().transpose()?, + r1.alignment_start().transpose()?, + r1.mate_reference_sequence_id().transpose()?, + r1.mate_alignment_start().transpose()?, r1.template_length(), ); @@ -214,12 +208,12 @@ mod tests { let actual = mate_key(&r1)?; let expected = ( - r1.read_name().map(|buf| buf.as_ref().to_vec()), + r1.name().map(|name| name.as_bytes().to_vec()), SegmentPosition::Last, - r1.mate_reference_sequence_id()?, - r1.mate_alignment_start()?, - r1.reference_sequence_id()?, - r1.alignment_start()?, + r1.mate_reference_sequence_id().transpose()?, + r1.mate_alignment_start().transpose()?, + r1.reference_sequence_id().transpose()?, + r1.alignment_start().transpose()?, -r1.template_length(), ); diff --git a/src/record_pairs/segment_position.rs b/src/record_pairs/segment_position.rs index 9bc7947..dfedc6f 100644 --- a/src/record_pairs/segment_position.rs +++ b/src/record_pairs/segment_position.rs @@ -20,10 +20,10 @@ impl SegmentPosition { #[error("neither read 1 nor read 2 flag is set")] pub struct TryFromFlagsError; -impl TryFrom for SegmentPosition { +impl TryFrom for SegmentPosition { type Error = TryFromFlagsError; - fn try_from(flags: sam::record::Flags) -> Result { + fn try_from(flags: sam::alignment::record::Flags) -> Result { if flags.is_first_segment() { Ok(SegmentPosition::First) } else if flags.is_last_segment() { @@ -48,7 +48,7 @@ mod tests { #[test] fn test_try_from_flag() { - use sam::record::Flags; + use sam::alignment::record::Flags; let flags = Flags::SEGMENTED | Flags::FIRST_SEGMENT; assert_eq!(SegmentPosition::try_from(flags), Ok(SegmentPosition::First)); diff --git a/tests/quantify_single_end_forward_test.rs b/tests/quantify_single_end_forward_test.rs index 07d0eb8..01f8686 100644 --- a/tests/quantify_single_end_forward_test.rs +++ b/tests/quantify_single_end_forward_test.rs @@ -1,6 +1,6 @@ use std::{env, fs, num::NonZeroUsize}; -use noodles::sam::record::MappingQuality; +use noodles::sam::alignment::record::MappingQuality; use squab::{commands::quantify, count::Filter, StrandSpecificationOption}; #[test]