Skip to content

Commit c7c7938

Browse files
committed
python fn on report_fragment
1 parent 5ff7e3f commit c7c7938

File tree

5 files changed

+169
-94
lines changed

5 files changed

+169
-94
lines changed

src/bedder_bed.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use crate::position::{Position, Positioned};
44
use crate::string::String;
55
pub use simplebed;
6-
use simplebed::{BedError, BedReader, BedRecord as SimpleBedRecord, BedValue};
6+
pub use simplebed::{BedError, BedReader, BedRecord as SimpleBedRecord, BedValue};
77
use std::io::{self, BufRead};
88
use std::path::{Path, PathBuf};
99
#[derive(Debug, Clone)]
@@ -29,6 +29,10 @@ impl BedRecord {
2929
);
3030
Self(record)
3131
}
32+
33+
pub fn push_field(&mut self, field: BedValue) {
34+
self.0.push_field(field);
35+
}
3236
}
3337

3438
impl crate::position::Positioned for BedRecord {

src/column.rs

+34-61
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
use crate::intersection::Intersections;
2-
use crate::py::CompiledPython;
3-
use crate::report_options::ReportOptions;
4-
use std::sync::Arc;
1+
use crate::py::{CompiledPython, PyReportFragment};
2+
use crate::report::ReportFragment;
53
#[derive(Debug, PartialEq)]
64
pub enum Value {
75
Int(i32),
@@ -64,18 +62,14 @@ pub trait ColumnReporter: std::fmt::Debug {
6462
fn description(&self) -> &str;
6563
fn number(&self) -> &Number;
6664

67-
fn value(
68-
&self,
69-
r: &Intersections,
70-
report_options: Arc<ReportOptions>,
71-
) -> Result<Value, ColumnError>;
65+
/// Each report fragment is a different line in the output. So we can't pass a report.
66+
fn value(&self, r: &ReportFragment) -> Result<Value, ColumnError>;
7267
}
7368

7469
pub enum ValueParser {
7570
PythonExpression(String),
7671
LuaExpression(String),
77-
// bool indicates whether we should use the intersection.report() constraints or just the count of overlaps
78-
Count(bool),
72+
Count,
7973
Sum,
8074
Bases,
8175
ChromStartEnd,
@@ -127,9 +121,7 @@ impl TryFrom<&str> for ValueParser {
127121
} else if let Some(rest) = s.strip_prefix("lua:") {
128122
Ok(ValueParser::LuaExpression(rest.to_string()))
129123
} else if s == "count" {
130-
Ok(ValueParser::Count(false))
131-
} else if s == "report_count" {
132-
Ok(ValueParser::Count(true))
124+
Ok(ValueParser::Count)
133125
} else if s == "sum" {
134126
Ok(ValueParser::Sum)
135127
} else if s == "bases" {
@@ -149,8 +141,7 @@ impl std::fmt::Display for ValueParser {
149141
match self {
150142
ValueParser::PythonExpression(s) => write!(f, "py:{}", s),
151143
ValueParser::LuaExpression(s) => write!(f, "lua:{}", s),
152-
ValueParser::Count(false) => write!(f, "count"),
153-
ValueParser::Count(true) => write!(f, "report_count"),
144+
ValueParser::Count => write!(f, "count"),
154145
ValueParser::Sum => write!(f, "sum"),
155146
ValueParser::Bases => write!(f, "bases"),
156147
ValueParser::ChromStartEnd => write!(f, "chrom_start_end"),
@@ -182,21 +173,10 @@ impl ColumnReporter for Column<'_> {
182173
&self.number
183174
}
184175

185-
fn value(
186-
&self,
187-
r: &Intersections,
188-
report_options: Arc<ReportOptions>,
189-
) -> Result<Value, ColumnError> {
176+
fn value(&self, r: &ReportFragment) -> Result<Value, ColumnError> {
190177
// TODO: accept writer and write to it directly.
191178
match &self.value_parser {
192-
Some(ValueParser::Count(false)) => {
193-
// Return the count of overlapping intervals
194-
Ok(Value::Int(r.overlapping.len() as i32))
195-
}
196-
Some(ValueParser::Count(true)) => {
197-
let report = r.report(&report_options);
198-
Ok(Value::Int(report.len() as i32))
199-
}
179+
Some(ValueParser::Count) => Ok(Value::Int(r.b.len() as i32)),
200180
Some(ValueParser::Sum) => {
201181
// Sum the scores of overlapping intervals if they exist
202182
// This is more complex as we need to extract scores from the intervals
@@ -207,47 +187,40 @@ impl ColumnReporter for Column<'_> {
207187
// Calculate total number of bases covered by overlapping intervals
208188
// Use the report functionality to get the base count
209189

210-
let report = r.report(&report_options);
211-
212-
let bases = report.count_bases_by_id();
213-
let total_bases: i32 = bases.iter().sum::<u64>() as i32;
190+
let bases =
191+
r.b.iter()
192+
.map(|b| {
193+
let b = b.try_lock().expect("failed to lock b interval in Bases");
194+
b.stop() - b.start()
195+
})
196+
.sum::<u64>() as i32;
214197

215-
Ok(Value::Int(total_bases))
198+
Ok(Value::Int(bases))
216199
}
217200
Some(ValueParser::ChromStartEnd) => {
218-
let base_interval = r
219-
.base_interval
220-
.try_lock()
221-
.expect("failed to lock base_interval");
222-
let s = format!(
223-
"{}\t{}\t{}",
224-
base_interval.chrom(),
225-
base_interval.start(),
226-
base_interval.stop()
227-
);
228-
Ok(Value::String(s))
201+
if let Some(a) = &r.a {
202+
let a = a
203+
.try_lock()
204+
.expect("failed to lock a interval in ChromStartEnd");
205+
let s = format!("{}:{}-{}", a.chrom(), a.start(), a.stop());
206+
Ok(Value::String(s))
207+
} else {
208+
Err(ColumnError::InvalidValue(format!(
209+
"No base interval for {}",
210+
r.id
211+
)))
212+
}
229213
}
230214
Some(ValueParser::OriginalInterval) => {
231215
// Return the original interval as a string
232-
let base_interval = r
233-
.base_interval
234-
.try_lock()
235-
.expect("failed to lock base_interval");
236-
let s = format!(
237-
"{}\t{}\t{}",
238-
base_interval.chrom(),
239-
base_interval.start(),
240-
base_interval.stop()
241-
);
242-
Ok(Value::String(s))
216+
unimplemented!("original_interval");
243217
}
244218
Some(ValueParser::PythonExpression(expr)) => {
245219
// For Python expressions, we should use the compiled Python object
246220
if let Some(py) = &self.py {
247221
// Convert intersection to PyIntersections and evaluate
248-
let py_intersection =
249-
crate::py::PyIntersections::new(r.clone(), report_options);
250-
match py.eval(py_intersection) {
222+
let py_fragment = PyReportFragment::new(r.clone());
223+
match py.eval(py_fragment) {
251224
Ok(result) => Ok(Value::String(result)),
252225
Err(e) => Err(ColumnError::PythonError(format!(
253226
"Python error when evaluating expression: \"{}\": {}",
@@ -269,7 +242,7 @@ impl ColumnReporter for Column<'_> {
269242
}
270243
None => {
271244
// Default behavior when no parser is specified - return count
272-
Ok(Value::Int(r.overlapping.len() as i32))
245+
Ok(Value::Int(r.b.len() as i32))
273246
}
274247
}
275248
}
@@ -364,7 +337,7 @@ impl TryFrom<&str> for Column<'_> {
364337
Type::Integer,
365338
"Count".to_string(),
366339
Number::One,
367-
Some(ValueParser::Count(false)),
340+
Some(ValueParser::Count),
368341
),
369342
"sum" => Column::new(
370343
"sum".to_string(),

0 commit comments

Comments
 (0)