7
7
use std:: slice;
8
8
use std:: ffi;
9
9
use std:: ops;
10
+ use std:: fmt;
10
11
11
12
use itertools:: Itertools ;
12
13
@@ -227,10 +228,10 @@ impl Record {
227
228
unsafe { slice:: from_raw_parts ( self . data ( ) [ self . qname_len ( ) ..] . as_ptr ( ) as * const u32 , self . cigar_len ( ) ) }
228
229
}
229
230
230
- /// Get cigar sequence . Complexity: O(k) with k being the length of the cigar string.
231
- pub fn cigar ( & self ) -> Vec < Cigar > {
231
+ /// Get cigar string . Complexity: O(k) with k being the length of the cigar string.
232
+ pub fn cigar ( & self ) -> CigarString {
232
233
let raw = self . raw_cigar ( ) ;
233
- raw. iter ( ) . map ( |& c| {
234
+ CigarString ( raw. iter ( ) . map ( |& c| {
234
235
let len = c >> 4 ;
235
236
match c & 0b1111 {
236
237
0 => Cigar :: Match ( len) ,
@@ -245,7 +246,7 @@ impl Record {
245
246
9 => Cigar :: Back ( len) ,
246
247
_ => panic ! ( "Unexpected cigar type" ) ,
247
248
}
248
- } ) . collect ( )
249
+ } ) . collect ( ) )
249
250
}
250
251
251
252
fn seq_len ( & self ) -> usize {
@@ -453,7 +454,7 @@ unsafe impl<'a> Send for Seq<'a> {}
453
454
unsafe impl < ' a > Sync for Seq < ' a > { }
454
455
455
456
456
- #[ derive( PartialEq , Debug ) ]
457
+ #[ derive( PartialEq , Eq , Debug , Clone ) ]
457
458
pub enum Cigar {
458
459
Match ( u32 ) , // M
459
460
Ins ( u32 ) , // I
@@ -483,8 +484,115 @@ impl Cigar {
483
484
Cigar :: Back ( len) => len << 4 | 9 ,
484
485
}
485
486
}
487
+
488
+ /// Return the length the CIGAR.
489
+ pub fn len ( & self ) -> u32 {
490
+ match * self {
491
+ Cigar :: Match ( len) => len,
492
+ Cigar :: Ins ( len) => len,
493
+ Cigar :: Del ( len) => len,
494
+ Cigar :: RefSkip ( len) => len,
495
+ Cigar :: SoftClip ( len) => len,
496
+ Cigar :: HardClip ( len) => len,
497
+ Cigar :: Pad ( len) => len,
498
+ Cigar :: Equal ( len) => len,
499
+ Cigar :: Diff ( len) => len,
500
+ Cigar :: Back ( len) => len
501
+ }
502
+ }
503
+
504
+ /// Return the character representing the CIGAR.
505
+ pub fn char ( & self ) -> char {
506
+ match * self {
507
+ Cigar :: Match ( _) => 'M' ,
508
+ Cigar :: Ins ( _) => 'I' ,
509
+ Cigar :: Del ( _) => 'D' ,
510
+ Cigar :: RefSkip ( _) => 'N' ,
511
+ Cigar :: SoftClip ( _) => 'S' ,
512
+ Cigar :: HardClip ( _) => 'H' ,
513
+ Cigar :: Pad ( _) => 'P' ,
514
+ Cigar :: Equal ( _) => '=' ,
515
+ Cigar :: Diff ( _) => 'X' ,
516
+ Cigar :: Back ( _) => 'B'
517
+ }
518
+ }
519
+ }
520
+
521
+
522
+ impl fmt:: Display for Cigar {
523
+ fn fmt ( & self , fmt : & mut fmt:: Formatter ) -> Result < ( ) , fmt:: Error > {
524
+ fmt. write_fmt ( format_args ! ( "{}{}" , self . len( ) , self . char ( ) ) )
525
+ }
486
526
}
487
527
488
528
489
529
unsafe impl Send for Cigar { }
490
530
unsafe impl Sync for Cigar { }
531
+
532
+
533
+ custom_derive ! {
534
+ /// A CIGAR string. This type wraps around a `Vec<Cigar>`.
535
+ ///
536
+ /// # Example
537
+ ///
538
+ /// ```
539
+ /// use rust_htslib::bam::record::{Cigar, CigarString};
540
+ ///
541
+ /// let cigar = CigarString(vec![Cigar::Match(100), Cigar::SoftClip(10)]);
542
+ ///
543
+ /// // access by index
544
+ /// assert_eq!(cigar[0], Cigar::Match(100));
545
+ /// // format into classical string representation
546
+ /// assert_eq!(format!("{}", cigar), "100M10S");
547
+ /// // iterate
548
+ /// for op in &cigar {
549
+ /// println!("{}", op);
550
+ /// }
551
+ /// ```
552
+ #[ derive( NewtypeDeref ,
553
+ NewtypeIndex ( usize ) ,
554
+ NewtypeIndexMut ( usize ) ,
555
+ PartialEq ,
556
+ Eq ,
557
+ NewtypeDebug ,
558
+ Clone
559
+ ) ]
560
+ pub struct CigarString ( pub Vec <Cigar >) ;
561
+ }
562
+
563
+
564
+ impl < ' a > IntoIterator for & ' a CigarString {
565
+ type Item = & ' a Cigar ;
566
+ type IntoIter = :: std:: slice:: Iter < ' a , Cigar > ;
567
+
568
+ fn into_iter ( self ) -> Self :: IntoIter {
569
+ ( & ( self . 0 ) ) . into_iter ( )
570
+ }
571
+ }
572
+
573
+
574
+ impl fmt:: Display for CigarString {
575
+ fn fmt ( & self , fmt : & mut fmt:: Formatter ) -> Result < ( ) , fmt:: Error > {
576
+ for op in self {
577
+ fmt. write_fmt ( format_args ! ( "{}{}" , op. len( ) , op. char ( ) ) ) ?;
578
+ }
579
+ Ok ( ( ) )
580
+ }
581
+ }
582
+
583
+
584
+ #[ cfg( test) ]
585
+ mod tests {
586
+ use super :: * ;
587
+
588
+ #[ test]
589
+ fn test_cigar_string ( ) {
590
+ let cigar = CigarString ( vec ! [ Cigar :: Match ( 100 ) , Cigar :: SoftClip ( 10 ) ] ) ;
591
+
592
+ assert_eq ! ( cigar[ 0 ] , Cigar :: Match ( 100 ) ) ;
593
+ assert_eq ! ( format!( "{}" , cigar) , "100M10S" ) ;
594
+ for op in & cigar {
595
+ println ! ( "{}" , op) ;
596
+ }
597
+ }
598
+ }
0 commit comments