diff --git a/src/group.rs b/src/group.rs index 6a78246..32f8f0c 100644 --- a/src/group.rs +++ b/src/group.rs @@ -1,5 +1,5 @@ use crate::duplicates::DuplicateMap; -use crate::io::{iter_duplicates, until_err, ReadType}; +use crate::io::{iter_duplicates, ReadType}; use std::io::prelude::*; @@ -16,45 +16,31 @@ use anyhow::Result; /// # Returns /// /// * `Result<()>` - Returns `Ok(())` if successful, or an error if an error occurs during processing. -pub fn group( - input: &str, - writer: &mut impl Write, - duplicates: DuplicateMap, -) -> Result<()> { - // Start with a placeholder error object. This will be mutated if there are errors during - // iteration through the reads. - let mut err = Ok(()); - - let duplicate_iterator = iter_duplicates( - input, - duplicates, - false, - )?; +pub fn group(input: &str, writer: &mut impl Write, duplicates: DuplicateMap) -> Result<()> { + let mut duplicate_iterator = iter_duplicates(input, duplicates, false)?; let mut count = 0usize; - duplicate_iterator - // iterate until an error is found, writing into &err - .scan(&mut err, until_err) - .try_for_each(|group| -> Result<()> { - count += 1; - if count % 500000 == 0 { - info!("Processed: {} reads", count); + let mut first = true; + while let Some(elem) = duplicate_iterator.next() { + count += 1; + if count % 500000 == 0 { + info!("Processed: {} reads", count); + } + + let mut group = elem?; + let group_size = group.records.len(); + for (idx, rec) in group.records.iter_mut().enumerate() { + if first { + first = false + } else { + writer.write_all(b"\n")? } - for rec in group.records.iter() { - // write to the output file - crate::io::write_read( - writer, - rec, - &group, - ReadType::Original, - true, - )? - } - - Ok(()) - })?; + rec.add_metadata(group.index, ReadType::Original, idx + 1, group_size, 0.0); + rec.write_fastq(writer)?; + } + } - err + Ok(()) } diff --git a/src/io.rs b/src/io.rs index fbc7dc2..4d713a0 100644 --- a/src/io.rs +++ b/src/io.rs @@ -73,6 +73,7 @@ impl Record { write!(self.id, " UT:Z:{read_type_label} UG:i:{umi_group}") .expect("String writing should not error"); + // don't report the group average quality if the readtype is Original or Ignored if !matches!(read_type, ReadType::Original | ReadType::Ignored) { write!(self.id, " QL:f:{avg_qual:.2}").expect("String writing should not error"); } @@ -268,32 +269,3 @@ where Some(Ok(rec)) } - -/// Utility function to extract the error from an iterator and stop iteration immediately. Useful -/// for iterators which yield a Result. -/// -/// # Returns -/// -/// This function returns an `Option`. If the item is `Ok`, it returns `Some(T)`. -/// If the item is `Err`, it updates `err` with the error and returns `None`. -/// -/// # Example -/// ``` -/// let mut err = Ok(()); -/// let items = vec![Ok(1), Ok(2), Err(anyhow!("error")), Ok(3)]; -/// let results: Vec<_> = items -/// .into_iter() -/// .scan(&mut err, until_err) -/// .collect(); -/// assert_eq!(results, vec![1, 2]); -/// assert!(err.is_err()); -/// ``` -pub fn until_err(err: &mut &mut anyhow::Result<()>, item: anyhow::Result) -> Option { - match item { - Ok(item) => Some(item), - Err(e) => { - **err = Err(e); - None - } - } -}