-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathposition.rs
155 lines (136 loc) · 4.62 KB
/
position.rs
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
155
use crate::string::String;
use std::fmt::{self, Debug};
use std::io;
use std::result;
/// A Value is a vector of integers, floats, or strings.
/// Often this will be a single value.
#[derive(Debug)]
pub enum Value {
Ints(Vec<i64>),
Floats(Vec<f64>),
Strings(Vec<String>),
}
/// Field is either an integer, as in a bed column
/// or a string, as in a vcf info field.
#[derive(Debug)]
pub enum Field {
String(String),
Int(usize),
}
/// Error returned when a field is not found.
#[derive(Debug)]
pub enum FieldError {
InvalidFieldIndex(usize),
InvalidFieldName(String),
}
impl fmt::Display for FieldError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FieldError::InvalidFieldIndex(i) => write!(f, "invalid column index: {}", i),
FieldError::InvalidFieldName(s) => write!(f, "invalid column name: {}", s),
}
}
}
impl std::error::Error for FieldError {}
/// A Positioned has a position in the genome. It is a bed-like (half-open) interval.
/// It also has a means to extract values from integer or string columns.
pub trait Positioned: Debug {
fn chrom(&self) -> &str;
/// 0-based start position.
fn start(&self) -> u64;
/// non-inclusive end;
fn stop(&self) -> u64;
// get back the original line?
//fn line(&self) -> &'a str;
}
pub trait Valued {
// extract a value from the Positioned object Col
fn value(&self, b: Field) -> result::Result<Value, FieldError>;
}
#[derive(Debug)]
pub enum Position {
Bed(crate::bedder_bed::Record<3>),
// Note: we use a Box here because a vcf Record is large.
Vcf(Box<crate::bedder_vcf::Record>),
Interval(crate::interval::Interval),
// catch-all in case we have another interval type.
#[cfg(feature = "dyn_positioned")]
Other(Box<dyn Positioned>),
}
impl Position {
#[inline]
pub fn chrom(&self) -> &str {
match self {
Position::Bed(b) => b.chrom(),
Position::Vcf(v) => v.chrom(),
Position::Interval(i) => &i.chrom,
#[cfg(feature = "dyn_positioned")]
Position::Other(o) => o.chrom(),
}
}
#[inline]
pub fn start(&self) -> u64 {
match self {
Position::Bed(b) => b.start(),
Position::Vcf(v) => v.start(),
Position::Interval(i) => i.start,
#[cfg(feature = "dyn_positioned")]
Position::Other(o) => o.start(),
}
}
#[inline]
pub fn stop(&self) -> u64 {
match self {
Position::Bed(b) => b.stop(),
Position::Vcf(v) => v.stop(),
Position::Interval(i) => i.stop,
#[cfg(feature = "dyn_positioned")]
Position::Other(o) => o.stop(),
}
}
}
#[cfg(feature = "dyn_positioned")]
impl Valued for Box<dyn Positioned> {
#[inline]
fn value(&self, f: Field) -> result::Result<Value, FieldError> {
self.value(f)
}
}
// Delegate the boxed version of this trait object to the inner object.
impl Positioned for Box<dyn Positioned> {
fn chrom(&self) -> &str {
self.as_ref().chrom()
}
fn start(&self) -> u64 {
self.as_ref().start()
}
fn stop(&self) -> u64 {
self.as_ref().stop()
}
}
impl PartialEq for dyn Positioned {
fn eq(&self, other: &dyn Positioned) -> bool {
self.start() == other.start()
&& self.stop() == other.stop()
&& self.chrom() == other.chrom()
}
}
/// PositionedIterator is an iterator over Positioned objects.
pub trait PositionedIterator {
/// A name for the iterator. This is most often the file path, perhaps with the line number appended.
/// Used to provide informative messages to the user.
fn name(&self) -> String;
/// return the next Positioned from the iterator.
/// It is fine for implementers to ignore `q`;
/// Some iterators may improve performance by using `q` to index-skip.
/// `q` will be Some only on the first call for a given query interval.
/// Calls where `q` is None should return the next Positioned in the iterator (file) that has not
/// been returned previously. Intervals should only be returned once (even across many identical query intervals)
/// and they should always be returned in order (querys will always be in order).
/// Thus, if the implementer heeds `q` it should check that the returned Positioned is greater than the previously
/// returned position (Positioned equal to previously returned position should have already been returned).
fn next_position(
&mut self,
q: Option<&Position>,
) -> Option<std::result::Result<Position, io::Error>>;
}