diff --git a/src/bam/flags.rs b/src/bam/flags.rs new file mode 100644 index 000000000..bacd01b09 --- /dev/null +++ b/src/bam/flags.rs @@ -0,0 +1,129 @@ +//! A module that provides an easier way to work with SAM flags. +//! It achieves this by providing a struct (`Flag`) with associated constants representing +//! flags. And the `is_in_flag()` and `is_not_in_flag()` functions that allow testing if specific flags are set or not set. +//! +//! ``` +//! use rust_htslib::bam::flags{Flag, is_in_flag, is_not_in_flag}; +//! let read_flag = record.flag(); // in general this is the way to obtain a flag. +//! let read_flag = 64; +//! assert_eq!(is_in_flag(read_flag, Flag::FIRST_IN_PAIR), true); +//! assert_eq!(is_not_in_flag(read_flag, Flag::MATE_UNMAPPED), true); +//! ``` +/// +/// This structure contains constants representing SAM flag values as u16. +/// Using this structure incurs no runtime cost. +/// +/// ``` +/// use rust_htslib::bam::flags::Flag; +/// // to get the value of a flag representing a read paired, and reversly mapped. +/// let flag = Flag::PAIRED + Flag::READ_RERVERSE; +/// +/// ``` +pub struct Flag; + +impl Flag { + pub const PAIRED: u16 = 1; + pub const PROPERLY_PAIRED: u16 = 2; + pub const READ_UNMAPPED: u16 = 4; + pub const MATE_UNMAPPED: u16 = 8; + pub const READ_RERVERSE: u16 = 16; + pub const MATE_REVERSE: u16 = 32; + pub const FIRST_IN_PAIR: u16 = 64; + pub const SECOND_IN_PAIR: u16 = 128; + pub const NOT_PRIMARY_ALN: u16 = 256; + pub const FAIL_QC: u16 = 512; + pub const DUPLICATE: u16 = 1024; + pub const SUPPLEMENTARY: u16 = 2048; +} + +pub fn is_not_in_flag(flag: u16, not_in: u16) -> bool { + //! This function uses bitwise operations to test if flags are not set + //! # Arguments + //! * `flag`: u16 - The record flag you want to test + //! * `not_in`: u16 - The flags you want to check if they are not set (use 0 for no test) + //! + //! # Usage: + //! example: let test if a flag is primary alignment and did not fail QC + //! ``` + //! use rust_htslib::bam::flags; + //! use rust_htslib::bam::flags::Flag; + //! let read_flag = 65; + //! assert_eq!(flags::is_not_in_flag(read_flag, Flag::NOT_PRIMARY_ALN + Flag::FAIL_QC), true); + //! ``` + //! let test that the read is mapped. + //! ``` + //! + //! use rust_htslib::bam::flags::{Flag, is_not_in_flag}; + //! let read_flag = 18; + //! assert_eq!(is_not_in_flag(read_flag, Flag::READ_UNMAPPED), true); + //! ``` + //! + if (not_in & flag) != 0 { + return false; + } + true +} +pub fn is_in_flag(flag: u16, in_: u16) -> bool { + //! This function uses bitwise operations to test if flags are set + //! # Arguments + //! * `flag`: u16 - The record flag you want to test + //! * `in_`: u16 - The flags you want to check if they are set (use 0 for no test) + //! + //! # Usage: + //! example: let test if a flag is both paired and first in pair + //! ``` + //! use rust_htslib::bam::flags::{Flag, is_in_flag}; + //! let read_flag = 65; + //! assert_eq!(is_in_flag(read_flag, Flag::PAIRED + Flag::FIRST_IN_PAIR), true); + //! ``` + + if (in_ & flag) != in_ { + return false; + } + true +} + +/* Deprecated +pub fn check_flag(flag: u16, in_: u16, not_in: u16) -> bool { + //! This function uses bitwise operations to test if flags are set or not. + //! + //! # Arguments + //! + //! * `flag`: u16 - The record flag you want to test + //! * `in_`: u16 - The flags you want to check if they are set (use 0 for no test) + //! * `not_in`: u16 - The flags you want to check if they are not set (use 0 for no test) + //! + //! # Usage: + //! example: let test if a flag is both paired and first in pair + //! ``` + //! use rust_htslib::bam::flags::{Flag, check_flag}; + //! let read_flag = 65; + //! assert_eq!(check_flag(read_flag, Flag::PAIRED + Flag::FIRST_IN_PAIR, 0), true); + //! ``` + //! let test that the read is mapped. READ_UNMAPPED + //! ``` + //! use rust_htslib::bam::flags::{Flag, check_flag}; + //! let read_flag = 18; + //! assert_eq!(check_flag(read_flag, 0, Flag::READ_UNMAPPED), true); + //! ``` + //! + //! Finally let do a more complexe real example test: + //! ``` + //! use rust_htslib::bam::flags::{Flag, check_flag}; + //! let read_flag = 19; + //! assert_eq!(check_flag(read_flag, Flag::PAIRED + Flag::PROPERLY_PAIRED + Flag::READ_RERVERSE , Flag::READ_UNMAPPED + Flag::MATE_UNMAPPED), true); + //! ``` + //! + //binary flag check + //assert that: - in_ is in n + // - not_in is not in n + // bitwise operation + if (not_in & flag) != 0 { + return false; + } + if (in_ & flag) != in_ { + return false; + } + return true; +} +*/ diff --git a/src/bam/mod.rs b/src/bam/mod.rs index b79bd89a2..a598429a2 100644 --- a/src/bam/mod.rs +++ b/src/bam/mod.rs @@ -7,6 +7,7 @@ pub mod buffer; pub mod ext; +pub mod flags; pub mod header; pub mod index; pub mod pileup; diff --git a/src/bam/sam_flag.rs b/src/bam/sam_flag.rs new file mode 100644 index 000000000..747743e92 --- /dev/null +++ b/src/bam/sam_flag.rs @@ -0,0 +1,87 @@ + + +//! A module that provides an easier way to work with SAM flags. +//! It achieves this by providing a struct (`SamFlag`) with associated constants representing +//! flags, and the `check_flag()` function that allows testing if specific flags are set or not set. +//! +//! For example, the following code tests if the read flag has the FIRST_IN_PAIR flag set and the MATE_UNMAPPED flag not set: +//! ``` +//! use rust_htslib::bam::{SamFlag, check_flag}; +//! # let read_flag = record.flag(); in general this is the way to obtian a flag. +//! let read_flag = 64; +//! assert_eq!(check_flag(read_flag, SamFlag::FIRST_IN_PAIR, SamFlag::MATE_UNMAPPED), true); +//! ``` + + +/// +/// This structure contains constants representing SAM flag values as u16. +/// Using this structure incurs no runtime cost. +/// +/// ``` +/// use rust_htslib::bam::{SamFlag}; +/// to get the value of a flag representing a read paired, and reversly mapped. +/// let flag = SamFlag::PAIRED + SamFlag::READ_RERVERSE; +/// +/// ``` +pub struct SamFlag; + + +impl SamFlag { + pub const PAIRED: u16 = 1; + pub const PROPERLY_PAIRED: u16 = 2; + pub const READ_UNMAPPED: u16 = 4; + pub const MATE_UNMAPPED: u16 = 8; + pub const READ_RERVERSE: u16 = 16; + pub const MATE_REVERSE: u16 = 32; + pub const FIRST_IN_PAIR: u16 = 64; + pub const SECOND_IN_PAIR: u16 = 128; + pub const NOT_PRIMARY_ALN: u16 = 256; + pub const FAIL_QC: u16 = 512; + pub const DUPLICATE: u16 = 1024; + pub const SUPPLEMENTARY: u16 = 2048; +} + + +pub fn check_flag(flag: u16, in_: u16, not_in: u16) -> bool { + + //! This function uses bitwise operations to test if flags are set or not. + //! + //! # Arguments + //! + //! * `flag`: u16 - The record flag you want to test + //! * `in_`: u16 - The flags you want to check if they are set (use 0 for no test) + //! * `not_in`: u16 - The flags you want to check if they are not set (use 0 for no test) + //! + //! # Usage: + //! example: let test if a flag is both paired and fisrt in pair + //! ``` + //! use rust_htslib::bam::{SamFlag, check_flag}; + //! let read_flag = 18 + //! assert_eq!(check_flag(read_flag, SamFlag::PAIRED +SamFlag::FIRST_IN_PAIR, 0), true); + //! ``` + //! let test that the read is mapped. READ_UNMAPPED + //! ``` + //! use rust_htslib::bam::{SamFlag, check_flag}; + //! let read_flag = 18 + //! assert_eq!(check_flag(read_flag, 0, SamFlag::READ_UNMAPPED), true); + //! ``` + //! + //! Finally let do a more complexe real example test: + //! ``` + //! use rust_htslib::bam::{SamFlag, check_flag}; + //! let read_flag = 19 + //! assert_eq!(check_flag(read_flag, SamFlag::PAIRED + SamFlag::PROPERLY_PAIRED + SamFlag::READ_RERVERSE , SamFlag::READ_UNMAPPED + SamFlag::MATE_UNMAPPED), true); + //! ``` + //! + //binary flag check + //assert that: - in_ is in n + // - not_in is not in n + // bitwise operation + if (not_in & flag) != 0 { + return false; + } + if (in_ & flag) != in_ { + return false; + } + return true; +}