@@ -22,7 +22,9 @@ use crate::htslib;
2222use crate :: utils;
2323
2424use bio_types:: alignment:: { Alignment , AlignmentMode , AlignmentOperation } ;
25+ use bio_types:: genome;
2526use bio_types:: sequence:: SequenceRead ;
27+ use bio_types:: strand:: ReqStrand ;
2628
2729/// A macro creating methods for flag access.
2830macro_rules! flag {
@@ -46,6 +48,7 @@ pub struct Record {
4648 pub inner : htslib:: bam1_t ,
4749 own : bool ,
4850 cigar : Option < CigarStringView > ,
51+ header : Option < HeaderView > ,
4952}
5053
5154unsafe impl Send for Record { }
@@ -109,6 +112,7 @@ impl Record {
109112 inner : unsafe { MaybeUninit :: zeroed ( ) . assume_init ( ) } ,
110113 own : true ,
111114 cigar : None ,
115+ header : None ,
112116 }
113117 }
114118
@@ -128,6 +132,7 @@ impl Record {
128132 } ,
129133 own : false ,
130134 cigar : None ,
135+ header : None ,
131136 }
132137 }
133138
@@ -162,6 +167,10 @@ impl Record {
162167 }
163168 }
164169
170+ pub fn set_header ( & mut self , header : HeaderView ) {
171+ self . header = Some ( header) ;
172+ }
173+
165174 pub ( super ) fn data ( & self ) -> & [ u8 ] {
166175 unsafe { slice:: from_raw_parts ( self . inner ( ) . data , self . inner ( ) . l_data as usize ) }
167176 }
@@ -224,6 +233,16 @@ impl Record {
224233 self . inner_mut ( ) . core . qual = mapq;
225234 }
226235
236+ /// Get strand information from record flags.
237+ pub fn strand ( & mut self ) -> ReqStrand {
238+ let reverse = self . flags ( ) & 0x10 != 0 ;
239+ if reverse {
240+ ReqStrand :: Reverse
241+ } else {
242+ ReqStrand :: Forward
243+ }
244+ }
245+
227246 /// Get raw flags.
228247 pub fn flags ( & self ) -> u16 {
229248 self . inner ( ) . core . flag
@@ -706,6 +725,39 @@ impl SequenceRead for Record {
706725 }
707726}
708727
728+ impl genome:: AbstractInterval for Record {
729+ /// Return contig name. Panics if record does not know its header (which happens if it has not been read from a file).
730+ fn contig ( & self ) -> & str {
731+ let tid = self . tid ( ) ;
732+ if tid < 0 {
733+ panic ! ( "invalid tid, must be at least zero" ) ;
734+ }
735+ str:: from_utf8 (
736+ self . header
737+ . as_ref ( )
738+ . expect (
739+ "header must be set (this is the case if the record has been read from a file)" ,
740+ )
741+ . tid2name ( tid as u32 ) ,
742+ )
743+ . expect ( "unable to interpret contig name as UTF-8" )
744+ }
745+
746+ /// Return genomic range covered by alignment. Panics if `Record::cache_cigar()` has not been called first or `Record::pos()` is less than zero.
747+ fn range ( & self ) -> ops:: Range < genome:: Position > {
748+ let end_pos = self
749+ . cigar_cached ( )
750+ . expect ( "cigar has not been cached yet, call cache_cigar() first" )
751+ . end_pos ( ) as u64 ;
752+
753+ if self . pos ( ) < 0 {
754+ panic ! ( "invalid position, must be positive" )
755+ }
756+
757+ self . pos ( ) as u64 ..end_pos
758+ }
759+ }
760+
709761/// Auxiliary record data.
710762#[ derive( Debug , Clone , Copy , PartialEq ) ]
711763pub enum Aux < ' a > {
@@ -1091,6 +1143,28 @@ impl CigarStringView {
10911143 pos
10921144 }
10931145
1146+ /// Get number of bases softclipped at the beginning of the alignment.
1147+ pub fn leading_softclips ( & self ) -> i64 {
1148+ self . first ( ) . map_or ( 0 , |cigar| {
1149+ if let Cigar :: SoftClip ( s) = cigar {
1150+ * s as i64
1151+ } else {
1152+ 0
1153+ }
1154+ } )
1155+ }
1156+
1157+ /// Get number of bases softclipped at the end of the alignment.
1158+ pub fn trailing_softclips ( & self ) -> i64 {
1159+ self . last ( ) . map_or ( 0 , |cigar| {
1160+ if let Cigar :: SoftClip ( s) = cigar {
1161+ * s as i64
1162+ } else {
1163+ 0
1164+ }
1165+ } )
1166+ }
1167+
10941168 /// For a given position in the reference, get corresponding position within read.
10951169 /// If reference position is outside of the read alignment, return None.
10961170 ///
0 commit comments