use std::ops::Range;
use crate::model::Coord;
use crate::model::block::BlockSlice;
use crate::ops::region;
use crate::ops::score::{self, ScoreOpts};
use crate::{Block, ByteSlice};
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Strand {
Forward,
Reverse,
}
impl Strand {
pub fn as_byte(self) -> u8 {
match self {
Strand::Forward => b'+',
Strand::Reverse => b'-',
}
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Strands {
pub query: Strand,
pub reference: Option<Strand>,
}
impl Strands {
pub fn is_translated(&self) -> bool {
self.reference.is_some()
}
pub fn reference_or_forward(&self) -> Strand {
self.reference.unwrap_or(Strand::Forward)
}
pub fn render<W: std::io::Write>(&self, out: &mut W) -> std::io::Result<()> {
out.write_all(&[self.query.as_byte()])?;
if let Some(reference) = self.reference {
out.write_all(&[reference.as_byte()])?;
}
Ok(())
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PslFlavor {
Psl,
Pslx,
}
#[derive(Debug, Clone)]
pub struct PslxSeq {
pub query_seq: ByteSlice,
pub reference_seq: ByteSlice,
}
#[derive(Debug, Clone)]
pub struct Psl {
pub matches: u32,
pub mismatches: u32,
pub rep_matches: u32,
pub n_count: u32,
pub query_num_insert: u32,
pub query_base_insert: u32,
pub reference_num_insert: u32,
pub reference_base_insert: u32,
pub query_size: Coord,
pub query_start: Coord,
pub query_end: Coord,
pub reference_size: Coord,
pub reference_start: Coord,
pub reference_end: Coord,
pub strands: Strands,
pub query_name: ByteSlice,
pub reference_name: ByteSlice,
pub blocks: BlockSlice,
pub seq: Option<PslxSeq>,
}
impl Psl {
pub fn query_name_str(&self) -> &str {
self.query_name.as_str().unwrap_or("")
}
pub fn reference_name_str(&self) -> &str {
self.reference_name.as_str().unwrap_or("")
}
pub fn query_name_bytes(&self) -> &[u8] {
self.query_name.as_bytes()
}
pub fn reference_name_bytes(&self) -> &[u8] {
self.reference_name.as_bytes()
}
pub fn block_count(&self) -> usize {
self.blocks.len()
}
pub fn flavor(&self) -> PslFlavor {
if self.seq.is_some() {
PslFlavor::Pslx
} else {
PslFlavor::Psl
}
}
pub fn is_protein(&self) -> bool {
score::is_protein(self)
}
pub fn size_mul(&self) -> u32 {
score::size_mul(self)
}
pub fn score(&self) -> i64 {
score::psl_score(self)
}
pub fn milli_bad(&self, is_mrna: bool) -> i32 {
score::milli_bad(self, ScoreOpts { is_mrna })
}
pub fn percent_id(&self, is_mrna: bool) -> f64 {
score::percent_id(self, ScoreOpts { is_mrna })
}
pub fn block(&self, i: usize) -> Option<Block> {
self.blocks.get(i)
}
pub fn query_block_forward(&self, i: usize) -> Range<Coord> {
region::query_block_forward(self, i)
}
pub fn reference_block_interval(&self, i: usize) -> Range<Coord> {
region::reference_block_interval(self, i)
}
pub fn overlaps_reference(&self, name: &[u8], start: Coord, end: Coord) -> bool {
region::overlaps_reference(self, name, start, end)
}
}
pub trait PslRecord {
fn matches(&self) -> u32;
fn mismatches(&self) -> u32;
fn rep_matches(&self) -> u32;
fn n_count(&self) -> u32;
fn query_num_insert(&self) -> u32;
fn query_base_insert(&self) -> u32;
fn reference_num_insert(&self) -> u32;
fn reference_base_insert(&self) -> u32;
fn strands(&self) -> Strands;
fn query_name(&self) -> &[u8];
fn query_size(&self) -> Coord;
fn query_start(&self) -> Coord;
fn query_end(&self) -> Coord;
fn reference_name(&self) -> &[u8];
fn reference_size(&self) -> Coord;
fn reference_start(&self) -> Coord;
fn reference_end(&self) -> Coord;
fn block_count(&self) -> usize;
fn block_sizes(&self) -> &[Coord];
fn query_starts(&self) -> &[Coord];
fn reference_starts(&self) -> &[Coord];
fn query_seq(&self) -> Option<&[u8]>;
fn reference_seq(&self) -> Option<&[u8]>;
}
impl PslRecord for Psl {
fn matches(&self) -> u32 {
self.matches
}
fn mismatches(&self) -> u32 {
self.mismatches
}
fn rep_matches(&self) -> u32 {
self.rep_matches
}
fn n_count(&self) -> u32 {
self.n_count
}
fn query_num_insert(&self) -> u32 {
self.query_num_insert
}
fn query_base_insert(&self) -> u32 {
self.query_base_insert
}
fn reference_num_insert(&self) -> u32 {
self.reference_num_insert
}
fn reference_base_insert(&self) -> u32 {
self.reference_base_insert
}
fn strands(&self) -> Strands {
self.strands
}
fn query_name(&self) -> &[u8] {
self.query_name.as_bytes()
}
fn query_size(&self) -> Coord {
self.query_size
}
fn query_start(&self) -> Coord {
self.query_start
}
fn query_end(&self) -> Coord {
self.query_end
}
fn reference_name(&self) -> &[u8] {
self.reference_name.as_bytes()
}
fn reference_size(&self) -> Coord {
self.reference_size
}
fn reference_start(&self) -> Coord {
self.reference_start
}
fn reference_end(&self) -> Coord {
self.reference_end
}
fn block_count(&self) -> usize {
self.blocks.len()
}
fn block_sizes(&self) -> &[Coord] {
self.blocks.sizes()
}
fn query_starts(&self) -> &[Coord] {
self.blocks.query_starts()
}
fn reference_starts(&self) -> &[Coord] {
self.blocks.reference_starts()
}
fn query_seq(&self) -> Option<&[u8]> {
self.seq.as_ref().map(|s| s.query_seq.as_bytes())
}
fn reference_seq(&self) -> Option<&[u8]> {
self.seq.as_ref().map(|s| s.reference_seq.as_bytes())
}
}