1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
// Copyright 2017 Nicholas Ingolia
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.
//! Trait shared across sequence locations -- spliced, contiguous, or
//! single-position.
use std::ops::Neg;
use crate::annot::contig::Contig;
use crate::annot::pos::Pos;
use crate::strand::*;
/// A trait for a sequence location -- a defined region on a named
/// chromosome (or other reference sequence), which may also have
/// defined strand information. The trait is generic over the type of
/// identifier for the reference sequence (allowing owned strings,
/// sequence IDs, and other options) and the strand information
/// (allowing type-level distinction between stranded and unstranded
/// annotations).
pub trait Loc {
type RefID;
type Strand;
/// Name of the reference sequence (chromosome name, etc.)
fn refid(&self) -> &Self::RefID;
/// Starting (lowest, left-most, 5'-most) position on the
/// reference sequence (0-based).
fn start(&self) -> isize;
/// Length of the region
fn length(&self) -> usize;
/// `Strand` of the position
fn strand(&self) -> Self::Strand
where
Self::Strand: Copy;
/// Map a sequence position on a reference sequence _into_ a
/// relative position within an annotated location on the
/// reference sequence.
///
/// The first position of the annotated location is mapped to a
/// position at 0, the next position of the annotated location is
/// mapped to a position at 1, and so forth. The annotated
/// location must have a known strandedness, which is taken into
/// account. For reverse-strand annotations, the 3'-most position
/// on the reference sequence is mapped to 0, and the strandedness
/// of the position is reversed. When the sequence position lies
/// on a different named reference sequence than the annotated
/// location, or doesn't fall within the annotated location, then
/// `None` is returned.
///
/// This function serves as an inverse of @pos_outof.
fn pos_into<T>(&self, pos: &Pos<Self::RefID, T>) -> Option<Pos<(), T>>
where
Self::RefID: Eq,
Self::Strand: Into<ReqStrand> + Copy,
T: Neg<Output = T> + Copy;
/// Map a relative position within an annotated location _out of_
/// that location onto the enclosing reference sequence.
///
/// Position 0 within the annotated location is mapped to the
/// first position of the annotated location, position 1 is mapped
/// to the subsequent position, and so forth. The annotated
/// location must have a known strandedness, which is taken into
/// account. For reverse-strand annotations, position 0 is mapped
/// to the 3'-most position of the reference sequence. When the
/// sequence position is either negative, or greater than the
/// length of the annotated location, then `None` is returned. The
/// reference name for the sequence position is discarded; the
/// mapped position receives a clone of the annotation's reference
/// sequence name.
///
/// This function serves as an inverse of @pos_into.
fn pos_outof<Q, T>(&self, pos: &Pos<Q, T>) -> Option<Pos<Self::RefID, T>>
where
Self::RefID: Clone,
Self::Strand: Into<ReqStrand> + Copy,
T: Neg<Output = T> + Copy;
fn contig_intersection<T>(&self, other: &Contig<Self::RefID, T>) -> Option<Self>
where
Self: ::std::marker::Sized,
Self::RefID: PartialEq + Clone,
Self::Strand: Copy;
/// Contiguous sequence location that fully covers the location.
fn contig(&self) -> Contig<Self::RefID, Self::Strand>
where
Self::RefID: Clone,
Self::Strand: Copy,
{
Contig::new(
self.refid().clone(),
self.start(),
self.length(),
self.strand(),
)
}
/// The first `Pos` in a location, on the annotated strand.
///
/// The first position in a zero-length annotation will be the
/// starting postion. This is the same as the first position in a
/// length-1 annotation, on either strand.
fn first_pos(&self) -> Pos<Self::RefID, Self::Strand>
where
Self::RefID: Clone,
Self::Strand: Into<ReqStrand> + Copy,
{
match self.strand().into() {
ReqStrand::Forward => Pos::new(self.refid().clone(), self.start(), self.strand()),
ReqStrand::Reverse => {
if self.length() == 0 {
Pos::new(self.refid().clone(), self.start(), self.strand())
} else {
Pos::new(
self.refid().clone(),
self.start() + (self.length() as isize) - 1,
self.strand(),
)
}
}
}
}
/// The last `Pos` in a location, on the annotated strand.
///
/// The last position in a zero-length annotation will be the
/// starting postion. This is the same as the last position in a
/// length-1 annotation, on either strand.
fn last_pos(&self) -> Pos<Self::RefID, Self::Strand>
where
Self::RefID: Clone,
Self::Strand: Into<ReqStrand> + Copy,
{
match self.strand().into() {
ReqStrand::Forward => {
if self.length() == 0 {
Pos::new(self.refid().clone(), self.start(), self.strand())
} else {
Pos::new(
self.refid().clone(),
self.start() + (self.length() as isize) - 1,
self.strand(),
)
}
}
ReqStrand::Reverse => Pos::new(self.refid().clone(), self.start(), self.strand()),
}
}
}