// ahda: Pseudoalignment compression and conversion between formats.
//
// Copyright 2025 Tommi Mäklin [tommi@maklin.fi].
//
// Copyrights in this project are retained by contributors. No copyright assignment
// is required to contribute to this project.
//
// Except as otherwise noted (below and/or in individual files), this
// project is licensed under the Apache License, Version 2.0
// <LICENSE-APACHE> or <http://www.apache.org/licenses/LICENSE-2.0> or
// the MIT license, <LICENSE-MIT> or <http://opensource.org/licenses/MIT>,
// at your option.
//
//! ahda is a library and a command-line client for:
//!
//! - Compressing plain text pseudoalignment data.
//! - Decompressing binary pseudoalignment data in any supported format.
//! - Converting between plain text pseudoalignment formats output by different tools.
//! - Concatenating non-overlapping binary alignment data.
//! - Performing set operations on compressed pseudoalignment data.
//!
//! The following plain text formats are supported:
//! - [Bifrost](https://github.com/pmelsted/bifrost)
//! - [Fulgor](https://github.com/jermp/fulgor)
//! - [Metagraph](https://github.com/ratschlab/metagraph) (`--query-mode labels` only)
//! - [SAM](https://samtools.github.io/hts-specs/SAMv1.pdf) (input only)
//! - [Themisto](https://github.com/algbio/themisto)
//!
//! An additional custom plain text format meant to display all data contained in the records is also provided:
//! - [Ahda .tsv](parser::ahda_tsv)
//!
//! The default format for plain text outputs is Ahda .tsv.
//!
//! Internally, ahda uses [roaring bitmaps](https://roaringbitmap.org/) to store
//! the pseudoalignments.
//!
//! ## Usage
//!
//! ### Command line
//!
//! The ahda CLI supports the following subcommands:
//! - `ahda encode` compress pseudoalignment data from a supported format.
//! - `ahda decode` decompress pseudoalignment data to a supported format.
//! - `ahda convert` convert between supported plain text formats.
//! - `ahda cat` concatenate binary data that doesn't contain duplicated queries.
//! - `ahda set` perform set operations on compressed pseudoalignment data.
//!
//! Note that `encode` may need access to the .fastq input file and the names of
//! the pseudoalignment targets. These are required to create an encoded record
//! that can be converted to any of the supported plain text formats, because
//! the plain text formats contain varying levels of information about the input
//! data.
//!
//! Encoding Themisto and Metagraph data can be performed without the .fastq
//! file by renaming the queries because the index of each query (in the .fastq
//! file) is provided in the plain text format.
//!
//! Encoding SAM and Bifrost data can be performed without the names of the
//! pseudoalignment targets because they are provided in the plain text format.
//!
//!
//! ### Rust API
//!
//! The API provides several functions for operating on structs that implement
//! [Read] and/or [Write]. These are meant for use cases where an entire stream
//! should be processed.
//!
//! For use cases requiring access to a single record at a time, the following
//! structs are provided:
//!
//! - [Decoder](decoder::Decoder): takes a [Read] containing the encoded bytes and decodes them into [PseudoAln].
//! - [BitmapDecoder](decoder::bitmap_decoder::BitmapDecoder): takes an iterator over the indexes of set bits and decodes them into [PseudoAln].
//! - [Encoder](encoder::Encoder): takes an iterator over [PseudoAln] records and encodes them into a `Vec<u8>`.
//! - [Parser](parser::Parser): takes a [Read] containing plain text pseudoalignment bytes and converts them into [PseudoAln].
//! - [Printer](printer::Printer): takes an iterator over [PseudoAln] records and formats them into plain text data.
//!
//! These structs can additionally be chained together to eg. read encoded data
//! and print it in a plain text format, or to parse plain text data and encode
//! it.
//!
//! See documentation for the appropriate functions or structs for usage examples.
//!
//! ### C++ API
//!
//! ahda provides a C++ API for encoding and decoding pseudoalignment data into
//! memory. The API is available with the feature `cxxbridge`.
//!
//! Encoding requires converting the pseudoalignment to a flattened form
//! and obtaining the indexes of the set bits (positive alignments) that should
//! be included in a bitmap representation.
//!
//! The encoding API supports writing either a complete .ahda record or one
//! block at a time.
//!
//! Decoding can be performed by reading the bytes of a full .ahda record into
//! memory, or by reading in one block at a time. The output from the decoding
//! API are the indexes of the set bits in the (flattened) bitmap
//! representation.
//!
//! The decoding API also supports reading in the target sequence names, the
//! query sequence names, and the positions of the query sequences in the
//! original query input.
//!
//! ## File format specification
//!
//! The binary .ahda file format has the following structure:
//!
//! ### File header and flags
//!
//! - A [FileHeader] consisting of exactly 32 bytes.
//! The header must start with the bytes `97, 104, 100, 97` indicating that
//! the binary file is an .ahda record, and must be followed by two bytes
//! indicating the [ahda library version](AhdaVersion). The library version is
//! followed by a single byte indicating the [ahda file format
//! version](AhdaFormatVersion). The remaining bytes in the header contain
//! information about the binary data contained in the file.
//!
//! - A [FileFlags] consisting of a variable number of
//! bytes. The number of bytes must be given in the `flags_len` field of
//! FileHeader. The FileFlags block may be compressed, in which case
//! `flags_len` must provide the number of compressed bytes. The [compression
//! method](MetadataCompression) used must be provided in the
//! `metadata_compression` field of FileHeader.
//!
//! The FileFlags block contains the name of the sample stored
//! within the file and the names of the alignment target sequences. The
//! alignment target sequences must be provided in the order that they appear in
//! the alignment.
//!
//! Each .ahda file must only have one FileHeader and FileFlags.
//!
//! ### Blocks
//!
//! Alignment data is stored in a number of blocks that follow the file header
//! and flags. Each block has the following structure:
//!
//! - A [BlockHeader](headers::block::BlockHeader) consisting of exactly 32 bytes. The
//! header contains information about the records stored in this block.
//!
//! - A [BlockFlags] consisting of a variable number of
//! bytes. The number of bytes must be given in the `flags_len` field of
//! BlockHeader. The BlockFlags block may be compressed, in which case
//! `flags_len` must provide the number of compressed bytes. The [compression
//! method](MetadataCompression) used must be provided in the
//! `metadata_compression` field of BlockHeader.
//!
//! - A block containing the (compressed) bitmap corresponding to the alignment
//! data. The [type of the bitmap](compression::BitmapType) must match the
//! `bitmap_type` field of BlockHeader. The number of bytes containing the
//! bitmap must be provided in the `block_len` field of BlockHeader.
//!
//! The BlockFlags block must contain the fields promised by the
//! `fields_present` field of FileHeader. The BlockFlags may contain additional
//! fields that are promised by the `fields_present` field of BlockHeader but
//! not by the FileHeader.
//!
//! Each .ahda block must consist of exactly one BlockHeader and BlockFlags. An
//! .ahda file may have any number of blocks.
//!
//! A valid .ahda file ends with a block and must not include a footer.
//!
use headers::file::FileHeader;
use headers::file::FileFlags;
use headers::block::BlockFlags;
use headers::block::read_block_header;
use headers::file::read_file_header;
use headers::file::read_file_flags;
use headers::file::build_file_header_and_flags;
use headers::file::encode_file_header;
use headers::file::encode_file_flags;
use compression::BitmapType;
use compression::BitmapHolder;
use compression::MetadataCompression;
use compression::roaringwrapper::unpack_block_roaring;
use std::collections::HashSet;
use std::io::Read;
use std::io::Write;
use roaring::treemap::RoaringTreemap;
#[cfg(feature = "cxxbridge")]
pub mod cxx_api;
pub mod compression;
pub mod headers;
pub mod decoder;
pub mod encoder;
pub mod errors;
pub mod parser;
pub mod printer;
type E = Box<dyn std::error::Error>;
const MASK_QUERIES: u16 = 1 << 0; // 0x0001
const MASK_QUERY_IDS: u16 = 1 << 1; // 0x0002
/// Ahda library version
///
/// A new variant must be added when the release version is incremented.
///
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub enum AhdaVersion {
#[default]
V0_1_0,
}
impl AhdaVersion {
pub fn from_le_bytes(bytes: [u8; 2]) -> Result<Self, E> {
let version_u16 = u16::from_le_bytes(bytes);
Self::from_u16(version_u16)
}
pub fn from_u16(val: u16) -> Result<Self, E> {
match val {
0 => Ok(AhdaVersion::V0_1_0),
_ => Err(Box::new(errors::AhdaVersionError)),
}
}
pub fn to_u16(&self) -> u16 {
match &self {
AhdaVersion::V0_1_0 => 0,
}
}
}
impl std::str::FromStr for AhdaVersion {
type Err = errors::AhdaVersionError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"0.1.0" => Ok(Self::V0_1_0),
_ => Err(errors::AhdaVersionError{}),
}
}
}
/// Ahda file format version
///
/// A new variant must be added when breaking changes are introduced.
///
/// Breaking changes should be avoided whenever possible.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub enum AhdaFormatVersion {
#[default]
V1_0_0,
}
impl AhdaFormatVersion {
pub fn from_u8(val: u8) -> Result<Self, E> {
match val {
0 => Ok(AhdaFormatVersion::V1_0_0),
_ => Err(Box::new(errors::AhdaFormatVersionErr)),
}
}
pub fn to_u8(&self) -> u8 {
match &self {
AhdaFormatVersion::V1_0_0 => 0,
}
}
}
/// Supported plain text formats.
#[non_exhaustive]
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub enum Format {
#[default]
AhdaTSV,
Bifrost,
Fulgor,
Metagraph,
#[cfg(feature = "sam")]
SAM,
Themisto,
}
impl std::str::FromStr for Format {
type Err = String; // Define an error type for parsing failures
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"bifrost" => Ok(Format::Bifrost),
"fulgor" => Ok(Format::Fulgor),
"metagraph" => Ok(Format::Metagraph),
#[cfg(feature = "sam")]
"sam" => Ok(Format::SAM),
"themisto" => Ok(Format::Themisto),
"ahda-tsv" => Ok(Format::AhdaTSV),
_ => Err(format!("'{}' is not a valid Format", s)),
}
}
}
impl std::fmt::Display for Format {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Format::Bifrost => write!(f, "bifrost"),
Format::Fulgor => write!(f, "fulgor"),
Format::Metagraph => write!(f, "metagraph"),
#[cfg(feature = "sam")]
Format::SAM => write!(f, "SAM"),
Format::Themisto => write!(f, "themisto"),
Format::AhdaTSV => write!(f, "ahda-tsv"),
}
}
}
impl Format {
/// Guess the input format from plaintext bytes
///
/// Supports:
/// - SAM
/// - Themisto
/// - Bifrost
/// - Fulgor
/// - Metagraph
///
/// ## Errors
/// ### [CorruptedInputErr](crate::errors::CorruptedInputErr)
/// Input bytes do not contain the expected data.
///
/// ### [AmbiguousInputFormatErr](crate::errors::AmbiguousInputFormatErr)
/// Input format is either fulgor or metagraph but cannot be inferred with certainty.
///
/// ### [UnrecognizedInputFormatErr](crate::errors::UnrecognizedInputFormatErr)
/// Could not infer input format.
///
pub fn from_bytes(
bytes: &[u8],
) -> Result<Self, E> {
let first_line: Vec<u8> = if bytes.contains(&b'\n') {
let linebreak = match bytes.iter().position(|x| *x == b'\n') {
Some(ret) => ret,
None => return Err(Box::new(crate::errors::CorruptedInputErr{})),
};
bytes[0..linebreak].to_vec()
} else {
bytes.to_vec()
};
#[cfg(feature = "sam")]
if bytes.len() > 2 {
let sam: bool = bytes[0] == b'@' && bytes[1] == b'H' && bytes[2] == b'D';
if sam {
return Ok(Format::SAM)
}
}
let not_themisto: bool = first_line.contains(&b'\t');
if !not_themisto {
return Ok(Format::Themisto)
}
let line = first_line.clone().iter().map(|x| *x as char).collect::<String>();
let mut records = line.split('\t');
let first_record = records.next().ok_or(crate::errors::CorruptedInputErr{})?;
let bifrost: bool = first_record == "query_name";
if bifrost {
return Ok(Format::Bifrost)
}
let ahda_tsv: bool = first_record == "query_index";
if ahda_tsv {
return Ok(Format::AhdaTSV)
}
let maybe_metagraph: bool = first_record.parse::<u32>().is_ok();
let next = records.next().ok_or(crate::errors::CorruptedInputErr{})?;
let fulgor: bool = next.parse::<u32>().is_ok();
if fulgor && maybe_metagraph {
return Err(Box::new(crate::errors::AmbiguousInputFormatErr{}))
}
if fulgor {
return Ok(Format::Fulgor)
}
if maybe_metagraph {
return Ok(Format::Metagraph)
}
Err(Box::new(crate::errors::UnrecognizedInputFormatErr{}))
}
}
/// Supported set operations for [decode_from_read_into_roaring].
#[non_exhaustive]
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub enum MergeOp {
#[default]
Union,
Intersection,
Xor,
Diff,
}
impl std::str::FromStr for MergeOp {
type Err = String; // Define an error type for parsing failures
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"union" => Ok(MergeOp::Union),
"intersection" => Ok(MergeOp::Intersection),
"xor" => Ok(MergeOp::Xor),
"diff" => Ok(MergeOp::Diff),
_ => Err(format!("'{}' is not a valid MergeOp", s)),
}
}
}
/// Options to functions that encode input data.
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq)]
pub struct EncodeOpts {
/// Force input data format for parsing plain text data.
pub format: Option<Format>,
/// Sample name to store in [FileFlags].
pub accession: Vec<u8>,
/// Store query names in the output [BlockFlags].
pub encode_query_names: bool,
/// Store alignment target name in the output records.
pub encode_target_names: bool,
/// Force bitmap type to use, see [BitmapType].
pub bitmap_type: Option<BitmapType>,
/// Metadata compression method, see [compression].
pub metadata_compression: MetadataCompression,
/// Rename queries using the scheme `accession`.`query_id`
pub rename_queries: bool,
}
impl Default for EncodeOpts {
/// Default to these values:
/// ```rust
/// let mut opts = ahda::EncodeOpts::default();
/// opts.format = None;
/// opts.accession = Vec::new();
/// opts.encode_query_names = false;
/// opts.encode_target_names = false;
/// opts.bitmap_type = None;
/// opts.metadata_compression = ahda::compression::MetadataCompression::Flate2;
/// opts.rename_queries = false;
/// # let expected = ahda::EncodeOpts::default();
/// # assert_eq!(opts, expected);
/// ```
///
fn default() -> EncodeOpts {
EncodeOpts {
format: None,
accession: Vec::new(),
encode_query_names: false,
encode_target_names: false,
bitmap_type: None,
metadata_compression: MetadataCompression::default(),
rename_queries: false,
}
}
}
/// A decompressed pseudoalignment record.
///
/// The fields are stored as Option to enable parsing them from incomplete
/// plaintext formats. If an incomplete alignment is parsed without using the
/// ahda API, this data must be filled in to create a valid .ahda record from
/// the encode API calls or with the [Encoder](crate::encoder::Encoder) class.
///
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct PseudoAln{
/// Indexes of positive alignment targets.
pub ones: Option<Vec<u32>>,
/// Names of positive alignment targets.
pub ones_names: Option<Vec<Vec<u8>>>,
/// Index of the query sequence in the query file.
pub query_id: Option<u32>,
/// Name of the query sequence in the query file.
pub query_name: Option<Vec<u8>>,
}
/// Merge compressed data by concatenating all blocks.
///
/// This simply appends the blocks in input order using [std::io::copy], it does
/// not check or modify the contents of the block header, block flags, or the
/// block data.
///
/// Updates the `n_queries` and `flags_len` fields in [FileHeader] to match the
/// new data.
///
/// Retains the `query_name` and `target_names` fields for [FileFlags] from the
/// first input.
///
/// ## Errors and panics
///
/// Panics if the [file headers](FileHeader) have different
/// number of targets or different target sequence names.
///
/// Errors if the input files contain duplicated queries. In this case, use a
/// set operation to merge the files with duplicates first.
///
/// ## Usage
///
/// ```rust
/// use ahda::{concatenate_from_read_to_write, decode_from_read, encode_to_write};
/// use ahda::EncodeOpts;
/// use ahda::PseudoAln;
/// use std::io::{Cursor, Seek};
///
/// // Set up mock inputs
/// let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()];
/// let queries = vec!["ERR4035126.1".as_bytes().to_vec(), "ERR4035126.2".as_bytes().to_vec(), "ERR4035126.651903".as_bytes().to_vec(), "ERR4035126.7543".as_bytes().to_vec(), "ERR4035126.16".as_bytes().to_vec()];
/// let name = "ERR4035126".as_bytes().to_vec();
///
/// let data_1 = vec![
/// PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(0), ones: Some(vec![0]), query_name: Some("ERR4035126.1".as_bytes().to_vec()) },
/// PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(1), ones: Some(vec![0]), query_name: Some("ERR4035126.2".as_bytes().to_vec()) },
/// ];
/// let data_2 = vec![
/// PseudoAln{ones_names: Some(vec!["plasmid.fasta".as_bytes().to_vec()]), query_id: Some(3), ones: Some(vec![1]), query_name: Some("ERR4035126.7543".as_bytes().to_vec()) },
/// PseudoAln{ones_names: Some(vec![]), query_id: Some(4), ones: Some(vec![]), query_name: Some("ERR4035126.16".as_bytes().to_vec()) },
/// ];
///
/// let mut data_bytes_1: Cursor<Vec<u8>> = Cursor::new(Vec::new());
/// let mut data_bytes_2: Cursor<Vec<u8>> = Cursor::new(Vec::new());
/// let mut opts = EncodeOpts::default();
/// opts.accession = name;
/// opts.encode_query_names = true;
///
/// // Encode the mock inputs to data_bytes_1 and data_bytes_2.
/// encode_to_write(&targets, &queries, data_1.clone(), &mut data_bytes_1, opts.clone()).unwrap();
/// encode_to_write(&targets, &queries, data_2.clone(), &mut data_bytes_2, opts.clone()).unwrap();
///
/// data_bytes_1.rewind();
/// data_bytes_2.rewind();
///
/// // Concatenate the data
/// let mut inputs = vec![data_bytes_1, data_bytes_2];
/// let mut output: Cursor<Vec<u8>> = Cursor::new(Vec::new());
///
/// concatenate_from_read_to_write(&mut inputs, &mut output, opts).unwrap();
/// output.rewind();
///
/// // output contains the alignments from data_1 and data_2
/// let (file_header, _file_flags, data_both) = decode_from_read(&mut output).unwrap();
///
/// assert_eq!(data_both[0..2], data_1);
/// assert_eq!(data_both[2..4], data_2);
/// ```
pub fn concatenate_from_read_to_write<R: Read, W: Write>(
conns: &mut [R],
conn_out: &mut W,
opts: EncodeOpts,
) -> Result<(), E> {
assert!(!conns.is_empty());
let mut headers: Vec<FileHeader> = Vec::with_capacity(conns.len());
let mut flags: Vec<FileFlags> = Vec::with_capacity(conns.len());
for conn in conns.iter_mut() {
let file_header = read_file_header(conn)?;
let file_flags = read_file_flags(&file_header, conn)?;
headers.push(file_header);
flags.push(file_flags);
}
let mut n_queries = 0_u32;
let n_targets = headers[0].n_targets;
let fields_present = headers[0].fields_present;
let target_names = flags[0].target_names.clone();
let query_name = flags[0].query_name.clone();
headers.into_iter().zip(flags).try_for_each(|(header, flags)| {
n_queries += header.n_queries;
if (n_targets != header.n_targets) || (target_names != flags.target_names) || (fields_present != header.fields_present) {
Err(Box::new(errors::IncompatibleFileHeadersErr{}))
} else {
Ok(())
}
})?;
let compression = opts.metadata_compression;
let (mut new_header, new_flags) = build_file_header_and_flags(&target_names, n_queries as usize, &query_name, &compression)?;
new_header.fields_present = fields_present;
let new_flags_bytes = encode_file_flags(&new_flags, &compression)?;
new_header.flags_len = new_flags_bytes.len() as u64;
let new_header_bytes = encode_file_header(&new_header)?;
conn_out.write_all(&new_header_bytes)?;
conn_out.write_all(&new_flags_bytes)?;
let mut seen_query_ids: HashSet<u32> = HashSet::with_capacity(new_header.n_queries as usize);
for conn_in in conns.iter_mut() {
while let Ok((mut block_header, block_flags)) = headers::block::read_block_header_and_flags(conn_in) {
block_header.metadata_compression = compression.to_u8();
let bytes = headers::block::encode_block_header_and_flags(&mut block_header, &block_flags)?;
if let Some(query_ids) = block_flags.query_ids {
query_ids.into_iter().try_for_each(|id| {
if !seen_query_ids.insert(id) {
return Err(Box::new(errors::DuplicatedQueriesErr{}))
}
Ok(())
})?;
} else {
return Err(Box::new(errors::QueryIdsNotFilled{}))
}
conn_out.write_all(&bytes)?;
let mut block_contents = conn_in.take(block_header.block_len as u64);
std::io::copy(&mut block_contents, conn_out)?;
}
}
conn_out.flush()?;
Ok(())
}
/// Convert plain text data from [Read] to plain text data to [Write].
///
/// Can read and write to any format supported by [Format].
///
/// ## Usage
///
/// ```rust
/// use ahda::convert_from_read_to_write;
/// use ahda::Format;
/// use std::io::Cursor;
///
/// // Mock themisto formatted data
///
/// // Have this input
/// // 3 0 2
/// // 0 2
/// // 4 0 1 2
/// // 2
///
/// let mut input_bytes: Vec<u8> = Vec::new();
/// input_bytes.append(&mut b"3 0 2\n".to_vec());
/// input_bytes.append(&mut b"0 2\n".to_vec());
/// input_bytes.append(&mut b"4 0 1 2\n".to_vec());
/// input_bytes.append(&mut b"2\n".to_vec());
/// let mut input: Cursor<Vec<u8>> = Cursor::new(input_bytes);
///
/// // Mock inputs
/// let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec(), "virus.fasta".as_bytes().to_vec()];
/// let queries = vec![b"1".to_vec(), b"2".to_vec(), b"651903".to_vec(), b"7543".to_vec(), b"16".to_vec()];
/// let name = "sample".as_bytes().to_vec();
///
/// // Convert to metagraph format
/// let out_format = Format::Metagraph;
/// let mut output: Vec<u8> = Vec::new();
/// let mut it = queries.into_iter();
/// let mut t_it = targets.into_iter();
/// convert_from_read_to_write(Some(&mut t_it), Some(&mut it), &name, out_format, &mut input, &mut output).unwrap();
///
/// // Expect to get this output:
/// // 3 7543 chr.fasta:virus.fasta
/// // 0 1 virus.fasta
/// // 4 16 chr.fasta:plasmid.fasta:virus.fasta
/// // 2 651903
/// //
/// let mut expected: Vec<u8> = Vec::new();
/// expected.append(&mut b"3\t7543\tchr.fasta:virus.fasta\n".to_vec());
/// expected.append(&mut b"0\t1\tvirus.fasta\n".to_vec());
/// expected.append(&mut b"4\t16\tchr.fasta:plasmid.fasta:virus.fasta\n".to_vec());
/// expected.append(&mut b"2\t651903\t\n".to_vec());
///
/// assert_eq!(output, expected);
/// ```
///
pub fn convert_from_read_to_write<R: Read, W: Write, T: Iterator<Item=Vec<u8>>, Q: Iterator<Item=Vec<u8>>>(
targets: Option<&mut T>,
queries: Option<&mut Q>,
sample_name: &[u8],
format: Format,
conn_in: &mut R,
conn_out: &mut W,
) -> Result<(), E> {
let reader = crate::parser::Parser::new(conn_in, queries, targets)?;
let n_queries = reader.len().unwrap_or(0);
let targets = if let Some(target_names) = reader.get_targets() {
target_names
} else {
let format = reader.format;
return Err(Box::new(errors::NeedTargetSequences { format }))
};
let mut reader_unwrapped = reader.map(|record| record.unwrap());
let writer = crate::printer::Printer::new(&mut reader_unwrapped, &targets, sample_name, n_queries, format)?;
for record in writer {
conn_out.write_all(&record?)?;
}
Ok(())
}
/// Encode from memory to something that implements [Write].
///
/// ## Errors and panics
///
/// Panics if the input `records` is empty
///
/// ## Usage
/// ```rust
/// use ahda::{encode_to_write, decode_from_read};
/// use ahda::EncodeOpts;
/// use ahda::PseudoAln;
/// use std::io::{Cursor, Seek};
///
/// // Mock data
/// let data = vec![
/// PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(0), ones: Some(vec![0]), query_name: Some("ERR4035126.1".as_bytes().to_vec()) },
/// PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(1), ones: Some(vec![0]), query_name: Some("ERR4035126.2".as_bytes().to_vec()) },
/// ];
///
/// let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()];
/// let queries = vec!["ERR4035126.1".as_bytes().to_vec(), "ERR4035126.2".as_bytes().to_vec(), "ERR4035126.651903".as_bytes().to_vec(), "ERR4035126.7543".as_bytes().to_vec(), "ERR4035126.16".as_bytes().to_vec()];
/// let name = "ERR4035126".as_bytes().to_vec();
/// let mut opts = EncodeOpts::default();
/// opts.accession = name;
/// opts.encode_query_names = true;
///
/// // Encode to `output`
/// let mut output: Cursor<Vec<u8>> = Cursor::new(Vec::new());
/// encode_to_write(&targets, &queries, data.clone(), &mut output, opts).unwrap();
///
/// // `output` can be decoded to get the original data back
/// output.rewind();
/// let (header, flags, decoded_data) = decode_from_read(&mut output).unwrap();
///
/// assert_eq!(decoded_data, data);
/// ```
///
pub fn encode_to_write<W: Write>(
targets: &[Vec<u8>],
queries: &[Vec<u8>],
records: Vec<PseudoAln>,
conn_out: &mut W,
opts: EncodeOpts,
) -> Result<(), E> {
assert!(!records.is_empty());
let n_records = queries.len().max(records.len());
let mut records_iter = records.into_iter().enumerate().map(|(idx, mut record)| {
if !opts.encode_query_names {
record.query_name = None;
}
if !opts.encode_target_names {
record.ones_names = None;
}
if opts.rename_queries {
let mut new_name: Vec<u8> = opts.accession.clone();
let mut idx_str: Vec<u8> = (idx + 1).to_string().as_bytes().to_vec();
new_name.append(&mut idx_str);
record.query_name = Some(new_name);
}
record
});
let mut encoder = encoder::Encoder::new(&mut records_iter, targets, &opts.accession, n_records)?;
encoder.set_metadata_compression(&opts.metadata_compression);
let bytes = encoder.encode_file_header_and_flags()?;
conn_out.write_all(&bytes)?;
for block in encoder.by_ref() {
conn_out.write_all(&block?)?;
}
Ok(())
}
/// Parse all plain-text pseudoalignments from [Read] and encode to memory.
///
/// ## Usage
/// ```rust
/// use ahda::{encode_from_read, decode_from_read_to_write};
/// use ahda::EncodeOpts;
/// use ahda::Format;
/// use std::io::{Cursor, Seek};
///
/// // Mock inputs
/// let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec(), "virus.fasta".as_bytes().to_vec()];
/// let queries = vec![b"r1".to_vec(), b"r2".to_vec(), b"r651903".to_vec(), b"r7543".to_vec(), b"r16".to_vec()];
/// let name = "sample".as_bytes().to_vec();
/// let mut opts = EncodeOpts::default();
/// opts.accession = name;
/// opts.encode_query_names = true;
///
/// // Have this input data:
/// // 3 r7543 chr.fasta:virus.fasta
/// // 0 r1 virus.fasta
/// // 4 r16 chr.fasta:plasmid.fasta:virus.fasta
/// // 2 r651903
/// //
/// let mut input_bytes: Vec<u8> = Vec::new();
/// input_bytes.append(&mut b"0\tr1\tvirus.fasta\n".to_vec());
/// input_bytes.append(&mut b"3\tr7543\tchr.fasta:virus.fasta\n".to_vec());
/// input_bytes.append(&mut b"4\tr16\tchr.fasta:plasmid.fasta:virus.fasta\n".to_vec());
/// input_bytes.append(&mut b"2\tr651903\t\n".to_vec());
///
/// let mut input: Cursor<Vec<u8>> = Cursor::new(input_bytes.clone());
/// let mut it = queries.into_iter();
/// let mut t_it = targets.into_iter();
/// let output = encode_from_read(Some(&mut t_it), Some(&mut it), &mut input, opts).unwrap();
///
/// // `output` can be decoded to get the original data back
/// let mut encoded: Cursor<Vec<u8>> = Cursor::new(output);
/// let mut decoded: Cursor<Vec<u8>> = Cursor::new(Vec::new());
/// decode_from_read_to_write(Format::Metagraph, &mut encoded, &mut decoded).unwrap();
///
/// assert_eq!(decoded.get_ref(), &input_bytes);
/// ```
///
pub fn encode_from_read<R: Read, T: Iterator<Item=Vec<u8>>, Q: Iterator<Item=Vec<u8>>>(
targets: Option<&mut T>,
queries: Option<&mut Q>,
conn_in: &mut R,
opts: EncodeOpts,
) -> Result<Vec<u8>, E> {
let have_queries = queries.is_some();
let mut reader = if let Some(format) = opts.format {
crate::parser::Parser::new_with_format(conn_in, queries, targets, format)?
} else {
crate::parser::Parser::new(conn_in, queries, targets)?
};
reader.fill_target_names(opts.encode_target_names);
reader.fill_query_name(opts.encode_query_names && have_queries);
let n_queries = reader.len().unwrap_or(0);
if !have_queries && reader.format != Format::Metagraph && reader.format != Format::Themisto && reader.format != Format::AhdaTSV {
return Err(Box::new(crate::errors::NeedQueryNamesErr{ format: reader.format }))
}
let targets = if let Some(target_names) = reader.get_targets() {
target_names
} else {
let format = reader.format;
return Err(Box::new(errors::NeedTargetSequences { format }))
};
let mut reader_unwrapped = reader.enumerate().map(|(idx, try_record)| {
let mut record = try_record.unwrap();
if !opts.encode_query_names {
record.query_name = None;
}
if !opts.encode_target_names {
record.ones_names = None;
}
if opts.rename_queries {
let mut new_name: Vec<u8> = opts.accession.clone();
let mut idx_str: Vec<u8> = (idx + 1).to_string().as_bytes().to_vec();
new_name.append(&mut idx_str);
record.query_name = Some(new_name);
}
record
});
let mut encoder = encoder::Encoder::new(&mut reader_unwrapped, &targets, &opts.accession, n_queries)?;
encoder.set_metadata_compression(&opts.metadata_compression);
let mut bytes = encoder.encode_file_header_and_flags()?;
for block in encoder.by_ref() {
bytes.append(&mut block?);
}
Ok(bytes)
}
/// Parse all plain-text pseudoalignments from [Read] and encode to [Write].
///
/// ## Usage
/// ```rust
/// use ahda::{encode_from_read_to_write, decode_from_read_to_write};
/// use ahda::Format;
/// use ahda::EncodeOpts;
/// use std::io::{Cursor, Seek};
///
/// // Mock inputs
/// let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec(), "virus.fasta".as_bytes().to_vec()];
/// let queries = vec![b"r1".to_vec(), b"r2".to_vec(), b"r651903".to_vec(), b"r7543".to_vec(), b"r16".to_vec()];
/// let name = "sample".as_bytes().to_vec();
///
/// // Have this input data:
/// // 3 r7543 chr.fasta:virus.fasta
/// // 0 r1 virus.fasta
/// // 4 r16 chr.fasta:plasmid.fasta:virus.fasta
/// // 2 r651903
/// //
/// let mut input_bytes: Vec<u8> = Vec::new();
/// input_bytes.append(&mut b"0\tr1\tvirus.fasta\n".to_vec());
/// input_bytes.append(&mut b"3\tr7543\tchr.fasta:virus.fasta\n".to_vec());
/// input_bytes.append(&mut b"4\tr16\tchr.fasta:plasmid.fasta:virus.fasta\n".to_vec());
/// input_bytes.append(&mut b"2\tr651903\t\n".to_vec());
///
/// let mut input: Cursor<Vec<u8>> = Cursor::new(input_bytes.clone());
///
/// let mut output: Cursor<Vec<u8>> = Cursor::new(Vec::new());
/// let mut it = queries.into_iter();
/// let mut t_it = targets.into_iter();
/// let mut opts = EncodeOpts::default();
/// opts.accession = name;
/// opts.encode_query_names = true;
/// encode_from_read_to_write(Some(&mut t_it), Some(&mut it), &mut input, &mut output, opts).unwrap();
///
/// // `output` can be decoded to get the original data back
/// output.rewind();
/// let mut decoded: Cursor<Vec<u8>> = Cursor::new(Vec::new());
/// decode_from_read_to_write(Format::Metagraph, &mut output, &mut decoded).unwrap();
///
/// assert_eq!(decoded.get_ref(), &input_bytes);
/// ```
///
pub fn encode_from_read_to_write<R: Read, W: Write, T: Iterator<Item=Vec<u8>>, Q: Iterator<Item=Vec<u8>>>(
targets: Option<&mut T>,
queries: Option<&mut Q>,
conn_in: &mut R,
conn_out: &mut W,
opts: EncodeOpts,
) -> Result<(), E> {
let have_queries = queries.is_some();
let mut reader = if let Some(format) = opts.format {
crate::parser::Parser::new_with_format(conn_in, queries, targets, format)?
} else {
crate::parser::Parser::new(conn_in, queries, targets)?
};
reader.fill_target_names(opts.encode_target_names);
reader.fill_query_name(opts.encode_query_names && have_queries && !opts.rename_queries);
let n_queries = reader.len().unwrap_or(0);
if !have_queries && reader.format != Format::Metagraph && reader.format != Format::Themisto && reader.format != Format::AhdaTSV {
return Err(Box::new(crate::errors::NeedQueryNamesErr{ format: reader.format }))
}
let targets = if let Some(target_names) = reader.get_targets() {
target_names
} else {
let format = reader.format;
return Err(Box::new(errors::NeedTargetSequences { format }))
};
let mut reader_unwrapped = reader.enumerate().map(|(idx, try_record)| {
let mut record = try_record.unwrap();
if !opts.encode_query_names {
record.query_name = None;
}
if !opts.encode_target_names {
record.ones_names = None;
}
if opts.rename_queries {
let mut new_name: Vec<u8> = opts.accession.clone();
let mut idx_str: Vec<u8> = (idx + 1).to_string().as_bytes().to_vec();
new_name.append(&mut idx_str);
record.query_name = Some(new_name);
}
record
});
let mut encoder = encoder::Encoder::new(&mut reader_unwrapped, &targets, &opts.accession, n_queries)?;
encoder.set_metadata_compression(&opts.metadata_compression);
let bytes = encoder.encode_file_header_and_flags()?;
conn_out.write_all(&bytes)?;
for block in encoder.by_ref() {
conn_out.write_all(&block?)?;
conn_out.flush()?;
}
Ok(())
}
/// Decode all pseudoalignments from [Read] and format to [Write].
///
/// ## Usage
/// ```rust
/// use ahda::{decode_from_read_to_write, encode_from_read_to_write};
/// use ahda::Format;
/// use ahda::EncodeOpts;
/// use std::io::{Cursor, Seek};
///
/// // Set up mock inputs
/// let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec(), "virus.fasta".as_bytes().to_vec()];
/// let queries = vec![b"r1".to_vec(), b"r2".to_vec(), b"r651903".to_vec(), b"r7543".to_vec(), b"r16".to_vec()];
/// let name = "sample".as_bytes().to_vec();
///
/// let mut plaintext_bytes: Vec<u8> = Vec::new();
/// plaintext_bytes.append(&mut b"0\tr1\tvirus.fasta\n".to_vec());
/// plaintext_bytes.append(&mut b"3\tr7543\tchr.fasta:virus.fasta\n".to_vec());
/// plaintext_bytes.append(&mut b"4\tr16\tchr.fasta:plasmid.fasta:virus.fasta\n".to_vec());
/// plaintext_bytes.append(&mut b"2\tr651903\t\n".to_vec());
///
/// // Encode mock data
/// let mut plaintext: Cursor<Vec<u8>> = Cursor::new(plaintext_bytes.clone());
/// let mut input: Cursor<Vec<u8>> = Cursor::new(Vec::new());
/// let mut it = queries.into_iter();
/// let mut t_it = targets.into_iter();
/// let mut opts = EncodeOpts::default();
/// opts.accession = name;
/// opts.encode_query_names = true;
/// encode_from_read_to_write(Some(&mut t_it), Some(&mut it), &mut plaintext, &mut input, opts).unwrap();
/// input.rewind();
///
/// // Decode all alignments and compare against the original inputs
/// let mut output: Cursor<Vec<u8>> = Cursor::new(Vec::new());
/// decode_from_read_to_write(Format::Metagraph, &mut input, &mut output).unwrap();
///
/// assert_eq!(output.get_ref(), plaintext.get_ref());
/// ```
///
pub fn decode_from_read_to_write<R: Read, W: Write>(
out_format: Format,
conn_in: &mut R,
conn_out: &mut W,
) -> Result<(), E> {
let mut decoder = decoder::Decoder::new(conn_in)?;
match out_format {
Format::Themisto => {
decoder.fill_target_names(false);
decoder.fill_query_name(false);
},
Format::Fulgor => {
decoder.fill_target_names(false);
decoder.fill_query_id(false);
},
Format::Bifrost => {
decoder.fill_target_names(false);
decoder.fill_query_id(false);
},
#[cfg(feature = "sam")]
Format::SAM => {
decoder.fill_target_names(false);
decoder.fill_query_id(false);
},
Format::Metagraph => {
decoder.fill_target_ids(false);
},
Format::AhdaTSV => {
decoder.fill_target_names(false);
},
}
let header = decoder.file_header().clone();
let flags = decoder.file_flags().clone();
let mut decoder_unwrapped = decoder.map(|block| block.unwrap());
let printer = printer::Printer::new_from_header_and_flags(&mut decoder_unwrapped, header.clone(), flags.clone(), out_format.clone())?;
for line in printer {
conn_out.write_all(&line?)?;
}
conn_out.flush()?;
Ok(())
}
/// Decode all pseudoalignments from [Read] to memory.
///
/// ## Usage
/// ```rust
/// use ahda::{decode_from_read, encode_to_write};
/// use ahda::EncodeOpts;
/// use ahda::PseudoAln;
/// use std::io::{Cursor, Seek};
///
/// // Mock data
/// let data = vec![
/// PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(0), ones: Some(vec![0]), query_name: Some("ERR4035126.1".as_bytes().to_vec()) },
/// PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(1), ones: Some(vec![0]), query_name: Some("ERR4035126.2".as_bytes().to_vec()) },
/// ];
///
/// let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()];
/// let queries = vec!["ERR4035126.1".as_bytes().to_vec(), "ERR4035126.2".as_bytes().to_vec(), "ERR4035126.651903".as_bytes().to_vec(), "ERR4035126.7543".as_bytes().to_vec(), "ERR4035126.16".as_bytes().to_vec()];
/// let name = "ERR4035126".as_bytes().to_vec();
/// let mut opts = EncodeOpts::default();
/// opts.accession = name;
/// opts.encode_query_names = true;
///
/// // Encode mock data
/// let mut input: Cursor<Vec<u8>> = Cursor::new(Vec::new());
/// encode_to_write(&targets, &queries, data.clone(), &mut input, opts).unwrap();
/// input.rewind();
///
/// // Decode to recover the original data
/// let (_file_header, _file_flags, alns) = decode_from_read(&mut input).unwrap();
///
/// assert_eq!(alns, data);
///
pub fn decode_from_read<R: Read>(
conn_in: &mut R,
) -> Result<(FileHeader, FileFlags, Vec<PseudoAln>), E> {
let decoder = decoder::Decoder::new(conn_in)?;
let header = decoder.file_header().clone();
let flags = decoder.file_flags().clone();
let mut alns: Vec<PseudoAln> = Vec::with_capacity(header.n_queries as usize);
let decoder_unwrapped = decoder.map(|block| block.unwrap());
alns.extend(decoder_unwrapped);
Ok((header, flags, alns))
}
/// Decode from memory and format to [Write].
///
/// ## Usage
/// ```rust
/// use ahda::{decode_to_write, encode_to_write};
/// use ahda::{Format, PseudoAln, EncodeOpts};
/// use std::io::{Cursor, Seek};
///
/// // Mock data
/// let data = vec![
/// PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(0), ones: Some(vec![0]), query_name: Some("ERR4035126.1".as_bytes().to_vec()) },
/// PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(1), ones: Some(vec![0]), query_name: Some("ERR4035126.2".as_bytes().to_vec()) },
/// ];
///
/// let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()];
/// let queries = vec!["ERR4035126.1".as_bytes().to_vec(), "ERR4035126.2".as_bytes().to_vec(), "ERR4035126.651903".as_bytes().to_vec(), "ERR4035126.7543".as_bytes().to_vec(), "ERR4035126.16".as_bytes().to_vec()];
/// let name = "ERR4035126".as_bytes().to_vec();
/// let mut opts = EncodeOpts::default();
/// opts.accession = name;
/// opts.encode_query_names = false;
///
/// // Encode mock data
/// let mut input: Cursor<Vec<u8>> = Cursor::new(Vec::new());
/// encode_to_write(&targets, &queries, data, &mut input, opts).unwrap();
///
/// // Decode to recover the original data
/// let mut output: Cursor<Vec<u8>> = Cursor::new(Vec::new());
/// decode_to_write(Format::Metagraph, input.get_ref(), &mut output).unwrap();
///
/// // Expect this output data:
/// // 0 ERR4035126.1 chr.fasta
/// // 1 ERR4035126.2 chr.fasta
/// let mut expected: Vec<u8> = Vec::new();
/// expected.append(&mut b"0\tERR4035126.1\tchr.fasta\n".to_vec());
/// expected.append(&mut b"1\tERR4035126.2\tchr.fasta\n".to_vec());
///
/// assert_eq!(output.get_ref(), &expected);
///
pub fn decode_to_write<W: Write>(
out_format: Format,
records: &[u8],
conn_out: &mut W,
) -> Result<(), E> {
let mut tmp = std::io::Cursor::new(&records);
let mut decoder = decoder::Decoder::new(&mut tmp)?;
match out_format {
Format::Themisto => {
decoder.fill_target_names(false);
decoder.fill_query_name(false);
},
Format::Fulgor => {
decoder.fill_target_names(false);
decoder.fill_query_id(false);
},
Format::Bifrost => {
decoder.fill_target_names(false);
decoder.fill_query_id(false);
},
#[cfg(feature = "sam")]
Format::SAM => {
decoder.fill_target_names(false);
decoder.fill_query_id(false);
},
Format::Metagraph => {
decoder.fill_target_ids(false);
},
Format::AhdaTSV => {
decoder.fill_target_names(false);
},
}
let header = decoder.file_header().clone();
let flags = decoder.file_flags().clone();
let mut decoder_unwrapped = decoder.map(|block| block.unwrap());
let printer = printer::Printer::new_from_header_and_flags(&mut decoder_unwrapped, header.clone(), flags.clone(), out_format.clone())?;
for line in printer {
conn_out.write_all(&line?)?;
}
conn_out.flush()?;
Ok(())
}
/// Reads the full bitmap and combined block flags from a file
///
/// Returns the [RoaringBitmap](roaring::RoaringBitmap) containing all
/// alignments from every block in the input, and the corresponding file header,
/// file flags, and block flags for a single block containing all the data.
///
/// ## Usage
///
/// ```rust
/// use ahda::{decode_from_read_to_roaring, encode_from_read_to_write};
/// use ahda::Format;
/// use ahda::EncodeOpts;
/// use ahda::headers::file::{FileHeader, FileFlags};
/// use ahda::headers::block::{BlockHeader, BlockFlags};
/// use roaring::RoaringTreemap;
/// use std::io::{Cursor, Seek};
///
/// // Set up mock inputs
/// let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec(), "virus.fasta".as_bytes().to_vec()];
/// let queries = vec![b"r1".to_vec(), b"r2".to_vec(), b"r651903".to_vec(), b"r7543".to_vec(), b"r16".to_vec()];
/// let name = "sample".as_bytes().to_vec();
///
/// let mut plaintext_bytes: Vec<u8> = Vec::new();
/// plaintext_bytes.append(&mut b"0\tr1\tvirus.fasta\n".to_vec());
/// plaintext_bytes.append(&mut b"3\tr7543\tchr.fasta:virus.fasta\n".to_vec());
/// plaintext_bytes.append(&mut b"4\tr16\tchr.fasta:plasmid.fasta:virus.fasta\n".to_vec());
/// plaintext_bytes.append(&mut b"2\tr651903\t\n".to_vec());
///
/// // Encode mock data
/// let mut plaintext: Cursor<Vec<u8>> = Cursor::new(plaintext_bytes.clone());
/// let mut input: Cursor<Vec<u8>> = Cursor::new(Vec::new());
/// let mut it = queries.into_iter();
/// let mut t_it = targets.into_iter();
/// let mut opts = EncodeOpts::default();
/// opts.accession = name;
/// opts.encode_query_names = true;
/// encode_from_read_to_write(Some(&mut t_it), Some(&mut it), &mut plaintext, &mut input, opts).unwrap();
/// input.rewind();
///
/// // Decode all alignments and compare against the original inputs
/// let (bitmap, file_header, file_flags, block_flags) = decode_from_read_to_roaring(&mut input).unwrap();
///
/// // Expect these outputs:
/// // RoaringTreemap<[2, 9, 11, 12, 13, 14]>
/// // FileHeader{
/// // n_targets: 3_u32,
/// // n_queries: 5_u32,
/// // ahda_header: ahda::headers::file::build_ahda_header().unwrap(),
/// // file_format: ahda::AhdaFormatVersion::V1_0_0.to_u8(),
/// // metadata_compression: ahda::compression::MetadataCompression::default().to_u8(),
/// // fields_present: 3,
/// // bitmap_type: ahda::compression::BitmapType::Roaring32.to_u16(),
/// // block_size: 65536_u32,
/// // flags_len: 46_u64,
/// // }
/// // FileFlags { query_name: "sample", target_names: vec!["chr.fasta", "plasmid.fasta", "virus.fasta"] }
/// // BlockFlags { queries: Some(["r1", "r651903", "r7543", "r16"]), query_ids: Some([0, 2, 3, 4]) }
///
/// assert_eq!(bitmap, RoaringTreemap::from([2, 9, 11, 12, 13, 14]));
/// assert_eq!(file_header, FileHeader{
/// n_targets: 3_u32,
/// n_queries: 5_u32,
/// ahda_header: ahda::headers::file::build_ahda_header().unwrap(),
/// file_format: ahda::AhdaFormatVersion::V1_0_0.to_u8(),
/// metadata_compression: ahda::compression::MetadataCompression::default().to_u8(),
/// fields_present: 3,
/// bitmap_type: ahda::compression::BitmapType::Roaring32.to_u16(),
/// block_size: 65536_u32,
/// flags_len: 55_u64,
/// });
/// let mut expected_flags = FileFlags::default();
/// expected_flags.query_name = "sample".as_bytes().to_vec();
/// expected_flags.target_names = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec(), "virus.fasta".as_bytes().to_vec()];
/// assert_eq!(file_flags, expected_flags);
/// assert_eq!(block_flags, BlockFlags{ queries: Some(vec!["r1".as_bytes().to_vec(), "r651903".as_bytes().to_vec(), "r7543".as_bytes().to_vec(), "r16".as_bytes().to_vec()]), query_ids: Some(vec![0, 2, 3, 4]) });
///
pub fn decode_from_read_to_roaring<R: Read>(
conn_in: &mut R,
) -> Result<(RoaringTreemap, FileHeader, FileFlags, BlockFlags), E> {
let mut bitmap_out = RoaringTreemap::new();
let header = crate::headers::file::read_file_header(conn_in)?;
let flags = crate::headers::file::read_file_flags(&header, conn_in)?;
let mut queries: Vec<Vec<u8>> = Vec::new();
let mut query_ids: Vec<u32> = Vec::new();
while let Ok(block_header) = read_block_header(conn_in) {
let deflated_len: usize = ((block_header.flags_len) + (block_header.block_len as u64)).try_into()?;
let mut block_bytes: Vec<u8> = vec![0; deflated_len];
conn_in.read_exact(&mut block_bytes)?;
let (bits, mut block_flags) = unpack_block_roaring(&block_bytes, &block_header)?;
let bitmap = match bits {
BitmapHolder::Roaring32(bitmap) => RoaringTreemap::from_bitmaps([(0, bitmap)]),
BitmapHolder::Roaring64(bitmap) => bitmap,
};
if let Some(block_names) = block_flags.queries.as_mut() {
queries.append(block_names);
}
if let Some(block_ids) = block_flags.query_ids.as_mut() {
query_ids.append(block_ids);
}
bitmap_out |= bitmap;
}
if !queries.is_empty() && !query_ids.is_empty() {
assert_eq!(queries.len(), query_ids.len());
let mut both: Vec<(u32, &Vec<u8>)> = queries.iter().zip(query_ids.iter()).map(|(name, idx)| (*idx, name)).collect();
both.sort_by_key(|x| x.0);
let queries: Option<Vec<Vec<u8>>> = Some(both.iter().map(|x| x.1.clone()).collect::<Vec<Vec<u8>>>());
let query_ids: Option<Vec<u32>> = Some(both.iter().map(|x| x.0).collect());
Ok((bitmap_out, header, flags, BlockFlags{ queries, query_ids }))
} else if queries.is_empty() {
query_ids.sort_unstable();
Ok((bitmap_out, header, flags, BlockFlags{ queries: None, query_ids: Some(query_ids) }))
} else {
Err(Box::new(crate::errors::QueryIdsNotFilled{}))
}
}
/// Merge bitmap from Read to an existing bitmap with Union
///
/// Doesn't check that the encoded data was created for compatible data, this
/// just merges the bitmaps.
///
/// ## Usage
///
/// ```rust
/// use ahda::{decode_from_read_into_roaring, decode_from_read_to_roaring, encode_from_read_to_write};
/// use ahda::MergeOp;
/// use ahda::EncodeOpts;
/// use roaring::RoaringTreemap;
/// use std::io::{Cursor, Seek};
///
/// // Set up mock inputs
/// let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec(), "virus.fasta".as_bytes().to_vec()];
/// let queries = vec![b"r1".to_vec(), b"r2".to_vec(), b"r651903".to_vec(), b"r7543".to_vec(), b"r16".to_vec()];
/// let name = "sample".as_bytes().to_vec();
///
/// // Have this input data in two files:
/// // 0 r1 virus.fasta
/// // 3 r7543 chr.fasta:virus.fasta
/// //
/// // 0 r1 plasmid.fasta:virus.fasta
/// // 3 r7543 plasmid.fasta
/// //
/// // ...and want to compute the intersection
///
/// let mut plaintext_bytes_1: Vec<u8> = Vec::new();
/// plaintext_bytes_1.append(&mut b"0\tr1\tvirus.fasta\n".to_vec());
/// plaintext_bytes_1.append(&mut b"3\tr7543\tchr.fasta:virus.fasta\n".to_vec());
///
/// let mut plaintext_bytes_2: Vec<u8> = Vec::new();
/// plaintext_bytes_2.append(&mut b"0\tr1\tplasmid.fasta:virus.fasta\n".to_vec());
/// plaintext_bytes_2.append(&mut b"3\tr7543\tplasmid.fasta\n".to_vec());
///
/// // Encode mock data
/// let mut plaintext_1: Cursor<Vec<u8>> = Cursor::new(plaintext_bytes_1.clone());
/// let mut input_1: Cursor<Vec<u8>> = Cursor::new(Vec::new());
/// let mut t_it = targets.iter().cloned();
/// let mut it = queries.iter().cloned();
/// let mut opts = EncodeOpts::default();
/// opts.accession = name;
/// opts.encode_query_names = true;
/// encode_from_read_to_write(Some(&mut t_it), Some(&mut it), &mut plaintext_1, &mut input_1, opts.clone()).unwrap();
/// input_1.rewind();
///
/// let mut plaintext_2: Cursor<Vec<u8>> = Cursor::new(plaintext_bytes_2.clone());
/// let mut input_2: Cursor<Vec<u8>> = Cursor::new(Vec::new());
/// let mut it = queries.into_iter();
/// let mut t_it = targets.into_iter();
/// encode_from_read_to_write(Some(&mut t_it), Some(&mut it), &mut plaintext_2, &mut input_2, opts).unwrap();
/// input_2.rewind();
///
/// // Decode data from `input_1`
/// let (mut bitmap, _file_header, _file_flags, _block_flags) = decode_from_read_to_roaring(&mut input_1).unwrap();
///
/// // Intersect data from `input_2` with the decoded `bitmap`
/// decode_from_read_into_roaring(&mut input_2, &MergeOp::Intersection, &mut bitmap).unwrap();
///
/// // Expect these outputs:
/// // RoaringBitmap<[2]>
/// // ...ie the alignment in the intersection is:
/// // 0 r1 virus.fasta
///
/// assert_eq!(bitmap, RoaringTreemap::from([2]));
///
pub fn decode_from_read_into_roaring<R: Read>(
conn_in: &mut R,
merge_op: &MergeOp,
bitmap_out: &mut RoaringTreemap,
) -> Result<(), E> {
match merge_op {
MergeOp::Intersection => {
// Have to read in the whole bitmap to perform intersection
let (bitmap_b, _, _, _) = decode_from_read_to_roaring(conn_in)?;
*bitmap_out &= bitmap_b;
},
_ => {
let header = crate::headers::file::read_file_header(conn_in)?;
let _ = crate::headers::file::read_file_flags(&header, conn_in)?;
while let Ok(block_header) = read_block_header(conn_in) {
let deflated_len: usize = ((block_header.flags_len) + (block_header.block_len as u64)).try_into()?;
let mut block_bytes: Vec<u8> = vec![0; deflated_len];
conn_in.read_exact(&mut block_bytes)?;
let (bits, _) = unpack_block_roaring(&block_bytes, &block_header)?;
let bitmap_b = match bits {
BitmapHolder::Roaring32(bitmap) => RoaringTreemap::from_bitmaps([(0, bitmap)]),
BitmapHolder::Roaring64(bitmap) => bitmap,
};
match merge_op {
MergeOp::Union => {
*bitmap_out |= bitmap_b;
},
MergeOp::Xor => {
*bitmap_out ^= bitmap_b;
},
MergeOp::Diff => {
*bitmap_out -= bitmap_b;
},
MergeOp::Intersection => {
unreachable!("MergeOp::Intersection cannot be performed block-wise.");
}
}
}
},
}
Ok(())
}
/// Merge bitmaps from Read(s) and write encoded result to Write.
pub fn merge_from_read_to_write<R: Read, W: Write>(
conn_in: &mut [R],
conn_out: &mut W,
merge_op: &MergeOp,
opts: EncodeOpts,
) -> Result<(), E> {
// Read first bitmap
let (mut bitmap_a, mut header_a, mut flags_a, mut block_flags) = decode_from_read_to_roaring(&mut conn_in[0])?;
for conn in conn_in.iter_mut().skip(1) {
decode_from_read_into_roaring(conn, merge_op, &mut bitmap_a)?;
}
if !opts.accession.is_empty() {
flags_a.query_name = opts.accession.clone();
}
let mut iter = bitmap_a.into_iter();
if header_a.n_queries == 0_u32 {
header_a.n_queries = block_flags.query_ids.as_ref().unwrap().len().try_into()?;
}
let mut encoder = encoder::bitmap_encoder::BitmapEncoder::new_from_header_and_flags(&mut iter, header_a, flags_a)?;
if opts.encode_query_names && !opts.rename_queries {
if let Some(query_names) = block_flags.queries {
encoder.set_query_names(&query_names);
} else {
return Err(Box::new(crate::errors::QueryNamesNotFilled {}))
}
} else if opts.encode_query_names && opts.rename_queries {
unimplemented!("Merge with renamed queries.");
if let Some(query_ids) = block_flags.query_ids {
let query_names = query_ids.iter().map(|query_id| {
let mut newname: Vec<u8> = opts.accession.clone();
newname.append(&mut query_id.to_string().as_bytes().to_vec());
newname
}).collect::<Vec<Vec<u8>>>();
encoder.set_query_names(&query_names);
} else {
return Err(Box::new(crate::errors::QueryIdsNotFilled {}))
}
} else {
unimplemented!("Merge without encoding query names.");
block_flags.queries = None;
}
encoder.set_metadata_compression(&opts.metadata_compression);
conn_out.write_all(&encoder.encode_file_header_and_flags()?)?;
for block in encoder {
conn_out.write_all(&block?)?;
}
conn_out.flush()?;
Ok(())
}
#[cfg(test)]
mod tests {
#[test]
fn guess_format_themisto() {
use super::Format;
let data: Vec<u8> = b"202678 1\n202728\n651964 0 1\n651966 0 1\n1166624 0\n1166625 0\n1166626 1".to_vec();
let got = Format::from_bytes(&data).unwrap();
let expected = Format::Themisto;
assert_eq!(got, expected);
}
#[test]
fn guess_format_fulgor() {
use super::Format;
let mut data: Vec<u8> = b"ERR4035126.4996\t0\n".to_vec();
data.append(&mut b"ERR4035126.1262953\t1\t0\n".to_vec());
data.append(&mut b"ERR4035126.1262954\t1\t1\n".to_vec());
let got = Format::from_bytes(&data).unwrap();
let expected = Format::Fulgor;
assert_eq!(got, expected);
}
#[test]
fn guess_format_bifrost() {
use super::Format;
let mut data: Vec<u8> = b"query_name\tchromosome.fasta\tplasmid.fasta\n".to_vec();
data.append(&mut b"ERR4035126.1262953\t1\t0\t15\n".to_vec());
data.append(&mut b"ERR4035126.1262954\t1\t1\t0\n".to_vec());
let got = Format::from_bytes(&data).unwrap();
let expected = Format::Bifrost;
assert_eq!(got, expected);
}
#[test]
fn guess_format_metagraph() {
use super::Format;
let mut data: Vec<u8> = b"30\tERR4035126.16\t\n".to_vec();
data.append(&mut b"15084\tERR4035126.7543\tplasmid.fasta\n".to_vec());
let got = Format::from_bytes(&data).unwrap();
let expected = Format::Metagraph;
assert_eq!(got, expected);
}
#[test]
#[cfg(feature = "sam")]
fn guess_format_sam() {
use super::Format;
let mut data: Vec<u8> = b"@HD\tVN:1.5\tSO:unsorted\tGO:query\n".to_vec();
data.append(&mut b"@SQ\tSN:OZ038621.1\tLN:5535987\n".to_vec());
data.append(&mut b"@SQ\tSN:OZ038622.1\tLN:104814\n".to_vec());
data.append(&mut b"@PG\tID:bwa\tPN:bwa\tVN:0.7.19-r1273\tCL:bwa mem -t 10 -o fwd_test.sam GCA_964037205.1_30348_1_60_genomic.fna ERR4035126_1.fastq.gz\n".to_vec());
data.append(&mut b"ERR4035126.1\t16\tOZ038621.1\t4541508\t60\t151M\t*\t0\t0\tAGTATTTAGTGACCTAAGTCAATAAAATTTTAATTTACTCACGGCAGGTAACCAGTTCAGAAGCTGCTATCAGACACTCTTTTTTTAATCCACACAGAGACATATTGCCCGTTGCAGTCAGAATGAAAAGCTGAAAATCACTTACTAAGGC FJ<<JJFJAA<-JFAJFAF<JFFJJJJJJJFJFJJA<A<AJJAAAFFJJJJFJJFJFJAJJ7JJJJJFJJJJJFFJFFJFJJJJJJFJ7FFJAJJJJJJJJFJJFJJFJFJJJJFJJFJJJJJJJJJFFJJJJJJJJJJJJJFJJJFFAAA\tNM:i:0\tMD:Z:151\tAS:i:151\tXS:i:0\n".to_vec());
let got = Format::from_bytes(&data).unwrap();
let expected = Format::SAM;
assert_eq!(got, expected);
}
#[test]
fn concatenate_from_read_to_write() {
use crate::compression::MetadataCompression;
use super::concatenate_from_read_to_write;
use super::EncodeOpts;
use std::io::Cursor;
let data_bytes_1: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 226, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 49, 50, 49, 48, 2, 0, 26, 63, 239, 0, 32, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 70, 6, 1, 48, 205, 196, 0, 0, 133, 36, 27, 152, 20, 0, 0, 0];
let data_bytes_2: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 37, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 18, 116, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 51, 53, 180, 52, 48, 230, 69, 18, 49, 52, 99, 100, 98, 98, 1, 0, 148, 139, 255, 106, 38, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 70, 6, 1, 6, 6, 6, 22, 6, 86, 6, 0, 21, 37, 56, 88, 20, 0, 0, 0];
let data_bytes_3: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 33, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 228, 119, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 55, 53, 49, 102, 100, 100, 6, 0, 66, 122, 30, 150, 21, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 128, 0, 1, 6, 6, 6, 118, 6, 0, 71, 48, 17, 238, 18, 0, 0, 0];
let data_1 = Cursor::new(data_bytes_1);
let data_2 = Cursor::new(data_bytes_2);
let data_3 = Cursor::new(data_bytes_3);
let mut data = vec![data_1, data_2, data_3];
let expected: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 226, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 49, 50, 49, 48, 2, 0, 26, 63, 239, 0, 32, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 70, 6, 1, 48, 205, 196, 0, 0, 133, 36, 27, 152, 20, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 37, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 18, 116, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 51, 53, 180, 52, 48, 230, 69, 18, 49, 52, 99, 100, 98, 98, 1, 0, 148, 139, 255, 106, 38, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 70, 6, 1, 6, 6, 6, 22, 6, 86, 6, 0, 21, 37, 56, 88, 20, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 33, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 228, 119, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 55, 53, 49, 102, 100, 100, 6, 0, 66, 122, 30, 150, 21, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 128, 0, 1, 6, 6, 6, 118, 6, 0, 71, 48, 17, 238, 18, 0, 0, 0];
let mut bytes_got: Cursor<Vec<u8>> = Cursor::new(Vec::new());
let mut opts = EncodeOpts::default();
opts.metadata_compression = MetadataCompression::Flate2;
opts.encode_query_names = true;
opts.rename_queries = false;
opts.accession = "ERR4035126".as_bytes().to_vec();
concatenate_from_read_to_write(&mut data, &mut bytes_got, opts).unwrap();
let got = bytes_got.get_mut();
assert_eq!(*got, expected);
}
#[test]
fn concatenate_from_read_to_write_with_multiple_blocks() {
use crate::compression::MetadataCompression;
use super::concatenate_from_read_to_write;
use super::EncodeOpts;
use std::io::Cursor;
let data_bytes_1: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 0, 3, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 2, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 10, 69, 82, 82, 52, 48, 51, 53, 49, 50, 54, 2, 9, 99, 104, 114, 46, 102, 97, 115, 116, 97, 13, 112, 108, 97, 115, 109, 105, 100, 46, 102, 97, 115, 116, 97, 2, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 226, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 49, 50, 49, 48, 2, 0, 26, 63, 239, 0, 32, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 70, 6, 1, 48, 205, 196, 0, 0, 133, 36, 27, 152, 20, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 37, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 18, 116, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 51, 53, 180, 52, 48, 230, 69, 18, 49, 52, 99, 100, 98, 98, 1, 0, 148, 139, 255, 106, 38, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 70, 6, 1, 6, 6, 6, 22, 6, 86, 6, 0, 21, 37, 56, 88, 20, 0, 0, 0];
let data_bytes_2: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 0, 3, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 10, 69, 82, 82, 52, 48, 51, 53, 49, 50, 54, 2, 9, 99, 104, 114, 46, 102, 97, 115, 116, 97, 13, 112, 108, 97, 115, 109, 105, 100, 46, 102, 97, 115, 116, 97, 1, 0, 0, 0, 1, 0, 0, 0, 33, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 228, 119, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 55, 53, 49, 102, 100, 100, 6, 0, 66, 122, 30, 150, 21, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 128, 0, 1, 6, 6, 6, 118, 6, 0, 71, 48, 17, 238, 18, 0, 0, 0];
let data_1 = Cursor::new(data_bytes_1);
let data_2 = Cursor::new(data_bytes_2);
let mut data = vec![data_1, data_2];
let expected: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 226, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 49, 50, 49, 48, 2, 0, 26, 63, 239, 0, 32, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 70, 6, 1, 48, 205, 196, 0, 0, 133, 36, 27, 152, 20, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 37, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 18, 116, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 51, 53, 180, 52, 48, 230, 69, 18, 49, 52, 99, 100, 98, 98, 1, 0, 148, 139, 255, 106, 38, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 70, 6, 1, 6, 6, 6, 22, 6, 86, 6, 0, 21, 37, 56, 88, 20, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 33, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 228, 119, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 55, 53, 49, 102, 100, 100, 6, 0, 66, 122, 30, 150, 21, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 128, 0, 1, 6, 6, 6, 118, 6, 0, 71, 48, 17, 238, 18, 0, 0, 0];
let mut bytes_got: Cursor<Vec<u8>> = Cursor::new(Vec::new());
let mut opts = EncodeOpts::default();
opts.metadata_compression = MetadataCompression::Flate2;
opts.encode_query_names = true;
opts.rename_queries = false;
opts.accession = "ERR4035126".as_bytes().to_vec();
concatenate_from_read_to_write(&mut data, &mut bytes_got, opts).unwrap();
let got = bytes_got.get_mut();
assert_eq!(*got, expected);
}
#[test]
fn concatenate_from_read_to_write_with_duplicated_queries_fails() {
use super::concatenate_from_read_to_write;
use super::EncodeOpts;
use std::io::Cursor;
let data_bytes_1: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 226, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 49, 50, 49, 48, 2, 0, 26, 63, 239, 0, 32, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 70, 6, 1, 48, 205, 196, 0, 0, 133, 36, 27, 152, 20, 0, 0, 0];
let data_bytes_2: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 37, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 18, 116, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 51, 53, 180, 52, 48, 230, 69, 18, 49, 52, 99, 100, 98, 98, 1, 0, 148, 139, 255, 106, 38, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 70, 6, 1, 6, 6, 6, 22, 6, 86, 6, 0, 21, 37, 56, 88, 20, 0, 0, 0];
let data_bytes_3: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 37, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 18, 116, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 51, 53, 180, 52, 48, 230, 69, 18, 49, 52, 99, 100, 98, 98, 1, 0, 148, 139, 255, 106, 38, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 70, 6, 1, 6, 6, 6, 22, 6, 86, 6, 0, 21, 37, 56, 88, 20, 0, 0, 0];
let data_1 = Cursor::new(data_bytes_1);
let data_2 = Cursor::new(data_bytes_2);
let data_3 = Cursor::new(data_bytes_3);
let mut data = vec![data_1, data_2, data_3];
let mut bytes_got: Cursor<Vec<u8>> = Cursor::new(Vec::new());
let opts = EncodeOpts::default();
let got = concatenate_from_read_to_write(&mut data, &mut bytes_got, opts);
assert!(got.is_err());
}
#[test]
fn concatenate_from_read_to_write_with_multiple_blocks_and_duplicated_queries_fails() {
use super::concatenate_from_read_to_write;
use super::EncodeOpts;
use std::io::Cursor;
let data_bytes_1: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 0, 3, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 2, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 10, 69, 82, 82, 52, 48, 51, 53, 49, 50, 54, 2, 9, 99, 104, 114, 46, 102, 97, 115, 116, 97, 13, 112, 108, 97, 115, 109, 105, 100, 46, 102, 97, 115, 116, 97, 2, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 226, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 49, 50, 49, 48, 2, 0, 26, 63, 239, 0, 32, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 70, 6, 1, 48, 205, 196, 0, 0, 133, 36, 27, 152, 20, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 39, 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 18, 116, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 51, 53, 180, 52, 48, 230, 71, 18, 49, 55, 53, 49, 102, 100, 98, 98, 6, 0, 108, 239, 38, 102, 40, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 38, 6, 1, 6, 6, 6, 22, 6, 86, 6, 54, 6, 0, 226, 13, 172, 28, 22, 0, 0, 0];
let data_bytes_2: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 0, 3, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 10, 69, 82, 82, 52, 48, 51, 53, 49, 50, 54, 2, 9, 99, 104, 114, 46, 102, 97, 115, 116, 97, 13, 112, 108, 97, 115, 109, 105, 100, 46, 102, 97, 115, 116, 97, 1, 0, 0, 0, 1, 0, 0, 0, 33, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 228, 119, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 55, 53, 49, 102, 100, 100, 6, 0, 66, 122, 30, 150, 21, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 128, 0, 1, 6, 6, 6, 118, 6, 0, 71, 48, 17, 238, 18, 0, 0, 0];
let data_1 = Cursor::new(data_bytes_1);
let data_2 = Cursor::new(data_bytes_2);
let mut data = vec![data_1, data_2];
let mut bytes_got: Cursor<Vec<u8>> = Cursor::new(Vec::new());
let opts = EncodeOpts::default();
let got = concatenate_from_read_to_write(&mut data, &mut bytes_got, opts);
assert!(got.is_err());
}
#[test]
fn concatenate_from_read_to_write_with_incompatible_headers_fails() {
use super::concatenate_from_read_to_write;
use super::EncodeOpts;
use std::io::Cursor;
let data_bytes_1: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 226, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 49, 50, 49, 48, 2, 0, 26, 63, 239, 0, 32, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 70, 6, 1, 48, 205, 196, 0, 0, 133, 36, 27, 152, 20, 0, 0, 0];
let data_bytes_2: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 37, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 18, 116, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 51, 53, 180, 52, 48, 230, 69, 18, 49, 52, 99, 100, 98, 98, 1, 0, 148, 139, 255, 106, 38, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 70, 6, 1, 6, 6, 6, 22, 6, 86, 6, 0, 21, 37, 56, 88, 20, 0, 0, 0];
let data_bytes_3: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 33, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 228, 119, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 55, 53, 49, 102, 100, 100, 6, 0, 66, 122, 30, 150, 21, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 128, 0, 1, 6, 6, 6, 118, 6, 0, 71, 48, 17, 238, 18, 0, 0, 0];
let data_1 = Cursor::new(data_bytes_1);
let data_2 = Cursor::new(data_bytes_2);
let data_3 = Cursor::new(data_bytes_3);
let mut data = vec![data_1, data_2, data_3];
let mut bytes_got: Cursor<Vec<u8>> = Cursor::new(Vec::new());
let opts = EncodeOpts::default();
let got = concatenate_from_read_to_write(&mut data, &mut bytes_got, opts);
assert!(got.is_err());
}
#[test]
fn convert_from_read_to_write() {
use super::convert_from_read_to_write;
use crate::Format;
use std::io::Cursor;
let data_bytes: Vec<u8> = vec![49, 9, 69, 82, 82, 52, 48, 51, 53, 49, 50, 54, 46, 50, 9, 99, 104, 114, 46, 102, 97, 115, 116, 97, 10, 48, 9, 69, 82, 82, 52, 48, 51, 53, 49, 50, 54, 46, 49, 9, 99, 104, 114, 46, 102, 97, 115, 116, 97, 10, 50, 9, 69, 82, 82, 52, 48, 51, 53, 49, 50, 54, 46, 54, 53, 49, 57, 48, 51, 9, 99, 104, 114, 46, 102, 97, 115, 116, 97, 58, 112, 108, 97, 115, 109, 105, 100, 46, 102, 97, 115, 116, 97, 10, 52, 9, 69, 82, 82, 52, 48, 51, 53, 49, 50, 54, 46, 49, 54, 9, 10, 51, 9, 69, 82, 82, 52, 48, 51, 53, 49, 50, 54, 46, 55, 53, 52, 51, 9, 112, 108, 97, 115, 109, 105, 100, 46, 102, 97, 115, 116, 97, 10];
let mut data = Cursor::new(data_bytes);
let expected = b"query_name\tchr.fasta\tplasmid.fasta\nERR4035126.2\t1\t0\nERR4035126.1\t1\t0\nERR4035126.651903\t1\t1\nERR4035126.16\t0\t0\nERR4035126.7543\t0\t1\n".to_vec();
let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()];
let queries = vec![b"ERR4035126.1".to_vec(), b"ERR4035126.2".to_vec(), b"ERR4035126.651903".to_vec(), b"ERR4035126.7543".to_vec(), b"ERR4035126.16".to_vec()];
let query_name ="ERR4035126".as_bytes().to_vec();
let out_format = Format::Bifrost;
let mut bytes_got: Cursor<Vec<u8>> = Cursor::new(Vec::new());
let mut it = queries.into_iter();
let mut t_it = targets.into_iter();
convert_from_read_to_write(Some(&mut t_it), Some(&mut it), &query_name, out_format, &mut data, &mut bytes_got).unwrap();
let got = bytes_got.get_ref();
assert_eq!(*got, expected);
}
#[test]
fn encode_to_write() {
use crate::compression::MetadataCompression;
use super::encode_to_write;
use super::EncodeOpts;
use crate::PseudoAln;
use std::io::Cursor;
let data = vec![
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(1), ones: Some(vec![0]), query_name: Some("ERR4035126.2".as_bytes().to_vec()) },
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(0), ones: Some(vec![0]), query_name: Some("ERR4035126.1".as_bytes().to_vec()) },
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()]), query_id: Some(2), ones: Some(vec![0, 1]), query_name: Some("ERR4035126.651903".as_bytes().to_vec()) },
PseudoAln{ones_names: Some(vec![]), query_id: Some(4), ones: Some(vec![]), query_name: Some("ERR4035126.16".as_bytes().to_vec()) },
PseudoAln{ones_names: Some(vec!["plasmid.fasta".as_bytes().to_vec()]), query_id: Some(3), ones: Some(vec![1]), query_name: Some("ERR4035126.7543".as_bytes().to_vec()) },
];
let mut bytes: Cursor<Vec<u8>> = Cursor::new(Vec::new());
let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()];
let queries = vec![
"ERR4035126.1".as_bytes().to_vec(),
"ERR4035126.2".as_bytes().to_vec(),
"ERR4035126.651903".as_bytes().to_vec(),
"ERR4035126.7543".as_bytes().to_vec(),
"ERR4035126.16".as_bytes().to_vec(),
];
let sample = "ERR4035126".as_bytes().to_vec();
let mut opts = EncodeOpts::default();
opts.accession = sample;
opts.encode_query_names = true;
opts.metadata_compression = MetadataCompression::Flate2;
encode_to_write(&targets, &queries, data, &mut bytes, opts).unwrap();
let expected: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 229, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 9, 34, 113, 204, 76, 13, 45, 13, 140, 249, 145, 68, 204, 77, 77, 140, 121, 145, 245, 154, 49, 178, 50, 48, 50, 49, 179, 0, 0, 22, 232, 102, 239, 83, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
assert_eq!(*bytes.get_ref(), expected);
}
#[test]
fn encode_to_write_without_query_names() {
use crate::compression::MetadataCompression;
use super::encode_to_write;
use super::EncodeOpts;
use crate::PseudoAln;
use std::io::Cursor;
let data = vec![
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(1), ones: Some(vec![0]), query_name: None },
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(0), ones: Some(vec![0]), query_name: None },
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()]), query_id: Some(2), ones: Some(vec![0, 1]), query_name: None },
PseudoAln{ones_names: Some(vec![]), query_id: Some(4), ones: Some(vec![]), query_name: None },
PseudoAln{ones_names: Some(vec!["plasmid.fasta".as_bytes().to_vec()]), query_id: Some(3), ones: Some(vec![1]), query_name: None },
];
let mut bytes: Cursor<Vec<u8>> = Cursor::new(Vec::new());
let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()];
let sample = "ERR4035126".as_bytes().to_vec();
let mut opts = EncodeOpts::default();
opts.accession = sample;
opts.metadata_compression = MetadataCompression::Flate2;
opts.encode_query_names = false;
opts.encode_target_names = false;
opts.rename_queries = false;
encode_to_write(&targets, &Vec::new(), data, &mut bytes, opts).unwrap();
let expected: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 96, 100, 101, 96, 100, 98, 102, 1, 0, 191, 97, 224, 4, 8, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
assert_eq!(*bytes.get_ref(), expected);
}
#[test]
fn encode_from_read() {
use super::encode_from_read;
use super::EncodeOpts;
use super::headers::file::build_file_header_and_flags;
use crate::PseudoAln;
use crate::Format;
use crate::compression::MetadataCompression;
use std::io::Cursor;
use std::io::Seek;
use std::io::Write;
let data = vec![
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(1), ones: Some(vec![0]), query_name: Some("ERR4035126.2".as_bytes().to_vec()) },
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(0), ones: Some(vec![0]), query_name: Some("ERR4035126.1".as_bytes().to_vec()) },
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()]), query_id: Some(2), ones: Some(vec![0, 1]), query_name: Some("ERR4035126.651903".as_bytes().to_vec()) },
PseudoAln{ones_names: Some(vec![]), query_id: Some(4), ones: Some(vec![]), query_name: Some("ERR4035126.16".as_bytes().to_vec()) },
PseudoAln{ones_names: Some(vec!["plasmid.fasta".as_bytes().to_vec()]), query_id: Some(3), ones: Some(vec![1]), query_name: Some("ERR4035126.7543".as_bytes().to_vec()) },
];
let mut bytes: Cursor<Vec<u8>> = Cursor::new(Vec::new());
let expected: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 229, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 9, 34, 113, 204, 76, 13, 45, 13, 140, 249, 145, 68, 204, 77, 77, 140, 121, 145, 245, 154, 49, 178, 50, 48, 50, 49, 179, 0, 0, 22, 232, 102, 239, 83, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()];
let queries = vec![b"ERR4035126.1".to_vec(), b"ERR4035126.2".to_vec(), b"ERR4035126.651903".to_vec(), b"ERR4035126.7543".to_vec(), b"ERR4035126.16".to_vec()];
let query_name ="ERR4035126".as_bytes().to_vec();
let mut opts = EncodeOpts::default();
opts.accession = query_name.clone();
opts.encode_query_names = true;
opts.metadata_compression = MetadataCompression::Flate2;
let (header, flags) = build_file_header_and_flags(&targets, queries.len(), &query_name, &opts.metadata_compression).unwrap();
let format = Format::Metagraph;
let mut tmp = data.into_iter();
let mut writer = crate::printer::Printer::new_from_header_and_flags(&mut tmp, header, flags, format).unwrap();
for record in writer.by_ref() {
bytes.write(&record.unwrap()).unwrap();
}
bytes.rewind().unwrap();
let mut it = queries.into_iter();
let mut t_it = targets.into_iter();
let got = encode_from_read(Some(&mut t_it), Some(&mut it), &mut bytes, opts).unwrap();
assert_eq!(got, expected);
}
#[test]
fn encode_from_read_without_query_names() {
use super::encode_from_read;
use super::EncodeOpts;
use super::headers::file::build_file_header_and_flags;
use crate::PseudoAln;
use crate::Format;
use crate::compression::MetadataCompression;
use std::io::Cursor;
use std::io::Seek;
use std::io::Write;
let data = vec![
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(1), ones: Some(vec![0]), query_name: None },
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(0), ones: Some(vec![0]), query_name: None },
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()]), query_id: Some(2), ones: Some(vec![0, 1]), query_name: None },
PseudoAln{ones_names: Some(vec![]), query_id: Some(4), ones: Some(vec![]), query_name: None },
PseudoAln{ones_names: Some(vec!["plasmid.fasta".as_bytes().to_vec()]), query_id: Some(3), ones: Some(vec![1]), query_name: None },
];
let mut bytes: Cursor<Vec<u8>> = Cursor::new(Vec::new());
let expected: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 96, 100, 101, 96, 100, 98, 102, 1, 0, 191, 97, 224, 4, 8, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()];
let queries = vec![b"ERR4035126.1".to_vec(), b"ERR4035126.2".to_vec(), b"ERR4035126.651903".to_vec(), b"ERR4035126.7543".to_vec(), b"ERR4035126.16".to_vec()];
let query_name ="ERR4035126".as_bytes().to_vec();
let compression = MetadataCompression::Flate2;
let mut opts = EncodeOpts::default();
opts.accession = query_name.clone();
opts.encode_query_names = true;
opts.metadata_compression = compression.clone();
let (header, flags) = build_file_header_and_flags(&targets, queries.len(), &query_name, &compression).unwrap();
let format = Format::Themisto;
let mut tmp = data.into_iter();
let mut writer = crate::printer::Printer::new_from_header_and_flags(&mut tmp, header, flags, format).unwrap();
for record in writer.by_ref() {
bytes.write(&record.unwrap()).unwrap();
}
bytes.rewind().unwrap();
let mut t_it = targets.into_iter();
let got = encode_from_read(Some(&mut t_it), None::<&mut std::iter::Empty<Vec<u8>>>, &mut bytes, opts).unwrap();
assert_eq!(got, expected);
}
#[test]
fn encode_from_read_to_write() {
use crate::compression::MetadataCompression;
use super::encode_from_read_to_write;
use super::EncodeOpts;
use std::io::Cursor;
let data_bytes: Vec<u8> = vec![49, 32, 48, 10, 48, 32, 48, 10, 50, 32, 48, 32, 49, 10, 52, 10, 51, 32, 49, 10];
let mut data = Cursor::new(data_bytes);
let expected: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 229, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 9, 34, 113, 204, 76, 13, 45, 13, 140, 249, 145, 68, 204, 77, 77, 140, 121, 145, 245, 154, 49, 178, 50, 48, 50, 49, 179, 0, 0, 22, 232, 102, 239, 83, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()];
let queries = vec![b"ERR4035126.1".to_vec(), b"ERR4035126.2".to_vec(), b"ERR4035126.651903".to_vec(), b"ERR4035126.7543".to_vec(), b"ERR4035126.16".to_vec()];
let query_name ="ERR4035126".as_bytes().to_vec();
let mut bytes_got: Cursor<Vec<u8>> = Cursor::new(Vec::new());
let mut it = queries.into_iter();
let mut t_it = targets.into_iter();
let mut opts = EncodeOpts::default();
opts.encode_query_names = true;
opts.accession = query_name;
opts.metadata_compression = MetadataCompression::Flate2;
encode_from_read_to_write(Some(&mut t_it), Some(&mut it), &mut data, &mut bytes_got, opts).unwrap();
let got = bytes_got.get_ref();
assert_eq!(*got, expected);
}
#[test]
fn encode_from_read_to_write_without_query_names() {
use crate::compression::MetadataCompression;
use super::encode_from_read_to_write;
use super::EncodeOpts;
use std::io::Cursor;
let data_bytes: Vec<u8> = vec![49, 9, 69, 82, 82, 52, 48, 51, 53, 49, 50, 54, 46, 50, 9, 99, 104, 114, 46, 102, 97, 115, 116, 97, 10, 48, 9, 69, 82, 82, 52, 48, 51, 53, 49, 50, 54, 46, 49, 9, 99, 104, 114, 46, 102, 97, 115, 116, 97, 10, 50, 9, 69, 82, 82, 52, 48, 51, 53, 49, 50, 54, 46, 54, 53, 49, 57, 48, 51, 9, 99, 104, 114, 46, 102, 97, 115, 116, 97, 58, 112, 108, 97, 115, 109, 105, 100, 46, 102, 97, 115, 116, 97, 10, 52, 9, 69, 82, 82, 52, 48, 51, 53, 49, 50, 54, 46, 49, 54, 9, 10, 51, 9, 69, 82, 82, 52, 48, 51, 53, 49, 50, 54, 46, 55, 53, 52, 51, 9, 112, 108, 97, 115, 109, 105, 100, 46, 102, 97, 115, 116, 97, 10];
let mut data = Cursor::new(data_bytes);
let expected: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 96, 100, 101, 96, 100, 98, 102, 1, 0, 191, 97, 224, 4, 8, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()];
let query_name ="ERR4035126".as_bytes().to_vec();
let mut bytes_got: Cursor<Vec<u8>> = Cursor::new(Vec::new());
let mut t_it = targets.into_iter();
let mut opts = EncodeOpts::default();
opts.accession = query_name;
opts.metadata_compression = MetadataCompression::Flate2;
opts.encode_query_names = false;
opts.rename_queries = false;
encode_from_read_to_write(Some(&mut t_it), None::<&mut std::iter::Empty<Vec<u8>>>, &mut data, &mut bytes_got, opts).unwrap();
let got = bytes_got.get_ref();
assert_eq!(*got, expected);
}
#[test]
fn decode_from_read() {
use super::decode_from_read;
use super::headers::file::build_file_header_and_flags;
use crate::PseudoAln;
use crate::compression::MetadataCompression;
use std::io::Cursor;
let mut expected_alns = vec![
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(1), ones: Some(vec![0]), query_name: Some("ERR4035126.2".as_bytes().to_vec()) },
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(0), ones: Some(vec![0]), query_name: Some("ERR4035126.1".as_bytes().to_vec()) },
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()]), query_id: Some(2), ones: Some(vec![0, 1]), query_name: Some("ERR4035126.651903".as_bytes().to_vec()) },
PseudoAln{ones_names: Some(vec![]), query_id: Some(4), ones: Some(vec![]), query_name: Some("ERR4035126.16".as_bytes().to_vec()) },
PseudoAln{ones_names: Some(vec!["plasmid.fasta".as_bytes().to_vec()]), query_id: Some(3), ones: Some(vec![1]), query_name: Some("ERR4035126.7543".as_bytes().to_vec()) },
];
expected_alns.sort_by_key(|x| *x.query_id.as_ref().unwrap());
let (mut expected_header, expected_flags) = build_file_header_and_flags(
&vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()],
5_usize,
&"ERR4035126".as_bytes().to_vec(),
&MetadataCompression::Flate2,
).unwrap();
expected_header.fields_present = 3_u16;
let data: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 229, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 9, 34, 113, 204, 76, 13, 45, 13, 140, 249, 145, 68, 204, 77, 77, 140, 121, 145, 245, 154, 49, 178, 50, 48, 50, 49, 179, 0, 0, 22, 232, 102, 239, 83, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let mut bytes: Cursor<Vec<u8>> = Cursor::new(data);
let (file_header, file_flags, mut got) = decode_from_read(&mut bytes).unwrap();
got.sort_by_key(|x| *x.query_id.as_ref().unwrap());
assert_eq!(expected_header, file_header);
assert_eq!(expected_flags, file_flags);
assert_eq!(expected_alns, got);
}
#[test]
fn decode_from_read_without_query_names() {
use super::decode_from_read;
use super::headers::file::build_file_header_and_flags;
use crate::PseudoAln;
use crate::compression::MetadataCompression;
use std::io::Cursor;
let mut expected_alns = vec![
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(1), ones: Some(vec![0]), query_name: Some("ERR4035126.2".as_bytes().to_vec()) },
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec()]), query_id: Some(0), ones: Some(vec![0]), query_name: Some("ERR4035126.1".as_bytes().to_vec()) },
PseudoAln{ones_names: Some(vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()]), query_id: Some(2), ones: Some(vec![0, 1]), query_name: Some("ERR4035126.3".as_bytes().to_vec()) },
PseudoAln{ones_names: Some(vec![]), query_id: Some(4), ones: Some(vec![]), query_name: Some("ERR4035126.5".as_bytes().to_vec()) },
PseudoAln{ones_names: Some(vec!["plasmid.fasta".as_bytes().to_vec()]), query_id: Some(3), ones: Some(vec![1]), query_name: Some("ERR4035126.4".as_bytes().to_vec()) },
];
expected_alns.sort_by_key(|x| *x.query_id.as_ref().unwrap());
let (mut expected_header, expected_flags) = build_file_header_and_flags(
&vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()],
5_usize,
&"ERR4035126".as_bytes().to_vec(),
&MetadataCompression::Flate2,
).unwrap();
expected_header.fields_present = 2_u16;
let data: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 96, 100, 101, 96, 100, 98, 102, 1, 0, 191, 97, 224, 4, 8, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let mut bytes: Cursor<Vec<u8>> = Cursor::new(data);
let (file_header, file_flags, mut got) = decode_from_read(&mut bytes).unwrap();
got.sort_by_key(|x| *x.query_id.as_ref().unwrap());
assert_eq!(expected_header, file_header);
assert_eq!(expected_flags, file_flags);
assert_eq!(expected_alns, got);
}
#[test]
fn decode_to_write() {
use super::decode_to_write;
use crate::Format;
use std::io::Cursor;
let expected = b"0\tERR4035126.1\tchr.fasta\n1\tERR4035126.2\tchr.fasta\n2\tERR4035126.651903\tchr.fasta:plasmid.fasta\n3\tERR4035126.7543\tplasmid.fasta\n4\tERR4035126.16\t\n";
let data: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 229, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 9, 34, 113, 204, 76, 13, 45, 13, 140, 249, 145, 68, 204, 77, 77, 140, 121, 145, 245, 154, 49, 178, 50, 48, 50, 49, 179, 0, 0, 22, 232, 102, 239, 83, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let format = Format::Metagraph;
let mut got_bytes: Cursor<Vec<u8>> = Cursor::new(Vec::new());
decode_to_write(format, &data, &mut got_bytes).unwrap();
let got = got_bytes.get_ref();
assert_eq!(*got, *expected);
}
#[test]
fn decode_to_write_without_query_names() {
use super::decode_to_write;
use crate::Format;
use std::io::Cursor;
let expected = b"0\tERR4035126.1\tchr.fasta\n1\tERR4035126.2\tchr.fasta\n2\tERR4035126.3\tchr.fasta:plasmid.fasta\n3\tERR4035126.4\tplasmid.fasta\n4\tERR4035126.5\t\n";
let data: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 96, 100, 101, 96, 100, 98, 102, 1, 0, 191, 97, 224, 4, 8, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let format = Format::Metagraph;
let mut got_bytes: Cursor<Vec<u8>> = Cursor::new(Vec::new());
decode_to_write(format, &data, &mut got_bytes).unwrap();
let got = got_bytes.get_ref();
assert_eq!(*got.iter().map(|x| *x as char).collect::<String>(), *expected.iter().map(|x| *x as char).collect::<String>());
}
#[test]
fn decode_from_read_to_write() {
use super::decode_from_read_to_write;
use crate::Format;
use std::io::Cursor;
let expected = b"0\tERR4035126.1\tchr.fasta\n1\tERR4035126.2\tchr.fasta\n2\tERR4035126.651903\tchr.fasta:plasmid.fasta\n3\tERR4035126.7543\tplasmid.fasta\n4\tERR4035126.16\t\n";
let data_bytes: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 229, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 9, 34, 113, 204, 76, 13, 45, 13, 140, 249, 145, 68, 204, 77, 77, 140, 121, 145, 245, 154, 49, 178, 50, 48, 50, 49, 179, 0, 0, 22, 232, 102, 239, 83, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let mut data: Cursor<Vec<u8>> = Cursor::new(data_bytes);
let format = Format::Metagraph;
let mut got_bytes: Cursor<Vec<u8>> = Cursor::new(Vec::new());
decode_from_read_to_write(format, &mut data, &mut got_bytes).unwrap();
let got = got_bytes.get_ref();
eprintln!("{:?}", got.iter().map(|x| *x as char).collect::<String>());
eprintln!("{:?}", expected.iter().map(|x| *x as char).collect::<String>());
assert_eq!(*got, *expected);
}
#[test]
fn decode_from_read_to_write_without_query_names() {
use super::decode_from_read_to_write;
use crate::Format;
use std::io::Cursor;
let expected = b"0\tERR4035126.1\tchr.fasta\n1\tERR4035126.2\tchr.fasta\n2\tERR4035126.3\tchr.fasta:plasmid.fasta\n3\tERR4035126.4\tplasmid.fasta\n4\tERR4035126.5\t\n";
let data_bytes: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 96, 100, 101, 96, 100, 98, 102, 1, 0, 191, 97, 224, 4, 8, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let mut data: Cursor<Vec<u8>> = Cursor::new(data_bytes);
let format = Format::Metagraph;
let mut got_bytes: Cursor<Vec<u8>> = Cursor::new(Vec::new());
decode_from_read_to_write(format, &mut data, &mut got_bytes).unwrap();
let got = got_bytes.get_ref();
assert_eq!(*got, *expected);
}
#[test]
fn decode_from_read_to_roaring() {
use super::decode_from_read_to_roaring;
use super::headers::file::build_file_header_and_flags;
use super::headers::block::BlockFlags;
use crate::compression::MetadataCompression;
use std::io::Cursor;
use roaring::RoaringTreemap;
let mut expected = RoaringTreemap::new();
expected.insert(0);
expected.insert(2);
expected.insert(4);
expected.insert(5);
expected.insert(7);
let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()];
let queries = vec!["ERR4035126.1".as_bytes().to_vec(), "ERR4035126.2".as_bytes().to_vec(), "ERR4035126.651903".as_bytes().to_vec(), "ERR4035126.7543".as_bytes().to_vec(), "ERR4035126.16".as_bytes().to_vec()];
let query_ids = vec![0, 1, 2, 3, 4];
let expected_block_flags = BlockFlags { queries: Some(queries.clone()), query_ids: Some(query_ids) };
let (mut expected_header, expected_flags) = build_file_header_and_flags(&targets, queries.len(), &"ERR4035126".as_bytes().to_vec(), &MetadataCompression::Flate2).unwrap();
expected_header.fields_present = 3_u16;
let data: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 229, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 9, 34, 113, 204, 76, 13, 45, 13, 140, 249, 145, 68, 204, 77, 77, 140, 121, 145, 245, 154, 49, 178, 50, 48, 50, 49, 179, 0, 0, 22, 232, 102, 239, 83, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let mut bytes: Cursor<Vec<u8>> = Cursor::new(data);
let (got, file_header, file_flags, block_flags) = decode_from_read_to_roaring(&mut bytes).unwrap();
assert_eq!(expected_header, file_header);
assert_eq!(expected_flags, file_flags);
assert_eq!(expected_block_flags, block_flags);
assert_eq!(got, expected);
}
#[test]
fn decode_from_read_to_roaring_without_query_names() {
use super::decode_from_read_to_roaring;
use super::headers::file::build_file_header_and_flags;
use super::headers::block::BlockFlags;
use crate::compression::MetadataCompression;
use std::io::Cursor;
use roaring::RoaringTreemap;
let mut expected = RoaringTreemap::new();
expected.insert(0);
expected.insert(2);
expected.insert(4);
expected.insert(5);
expected.insert(7);
let targets = vec!["chr.fasta".as_bytes().to_vec(), "plasmid.fasta".as_bytes().to_vec()];
let query_ids = vec![0, 1, 2, 3, 4];
let expected_block_flags = BlockFlags { queries: None, query_ids: Some(query_ids) };
let (mut expected_header, expected_flags) = build_file_header_and_flags(&targets, 0, &"ERR4035126".as_bytes().to_vec(), &MetadataCompression::Flate2).unwrap();
expected_header.fields_present = 2_u16;
let data: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 96, 100, 101, 96, 100, 98, 102, 1, 0, 191, 97, 224, 4, 8, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let mut bytes: Cursor<Vec<u8>> = Cursor::new(data);
let (got, file_header, file_flags, block_flags) = decode_from_read_to_roaring(&mut bytes).unwrap();
assert_eq!(expected_header, file_header);
assert_eq!(expected_flags, file_flags);
assert_eq!(expected_block_flags, block_flags);
assert_eq!(got, expected);
}
#[test]
fn decode_from_read_into_roaring_union() {
use super::decode_from_read_into_roaring;
use super::MergeOp;
use std::io::Cursor;
use roaring::RoaringTreemap;
let data_right: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 229, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 9, 34, 113, 204, 76, 13, 45, 13, 140, 249, 145, 68, 204, 77, 77, 140, 121, 145, 245, 154, 49, 178, 50, 48, 50, 49, 179, 0, 0, 22, 232, 102, 239, 83, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let mut data: Cursor<Vec<u8>> = Cursor::new(data_right);
let mut data_left = RoaringTreemap::new();
data_left.insert(1);
data_left.insert(5);
data_left.insert(8);
let mut expected = RoaringTreemap::new();
expected.insert(0);
expected.insert(1);
expected.insert(2);
expected.insert(4);
expected.insert(5);
expected.insert(7);
expected.insert(8);
decode_from_read_into_roaring(&mut data, &MergeOp::Union, &mut data_left).unwrap();
assert_eq!(data_left, expected);
}
#[test]
fn decode_from_read_into_roaring_intersection() {
use super::decode_from_read_into_roaring;
use super::MergeOp;
use std::io::Cursor;
use roaring::RoaringTreemap;
let data_right: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 229, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 9, 34, 113, 204, 76, 13, 45, 13, 140, 249, 145, 68, 204, 77, 77, 140, 121, 145, 245, 154, 49, 178, 50, 48, 50, 49, 179, 0, 0, 22, 232, 102, 239, 83, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let mut data: Cursor<Vec<u8>> = Cursor::new(data_right);
let mut data_left = RoaringTreemap::new();
data_left.insert(0);
data_left.insert(3);
data_left.insert(7);
let mut expected = RoaringTreemap::new();
expected.insert(0);
expected.insert(7);
decode_from_read_into_roaring(&mut data, &MergeOp::Intersection, &mut data_left).unwrap();
assert_eq!(data_left, expected);
}
#[test]
fn decode_from_read_into_roaring_xor() {
use super::decode_from_read_into_roaring;
use super::MergeOp;
use std::io::Cursor;
use roaring::RoaringTreemap;
let data_right: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 229, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 9, 34, 113, 204, 76, 13, 45, 13, 140, 249, 145, 68, 204, 77, 77, 140, 121, 145, 245, 154, 49, 178, 50, 48, 50, 49, 179, 0, 0, 22, 232, 102, 239, 83, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let mut data: Cursor<Vec<u8>> = Cursor::new(data_right);
let mut data_left = RoaringTreemap::new();
data_left.insert(0);
data_left.insert(1);
data_left.insert(5);
data_left.insert(7);
let mut expected = RoaringTreemap::new();
expected.insert(1);
expected.insert(2);
expected.insert(4);
decode_from_read_into_roaring(&mut data, &MergeOp::Xor, &mut data_left).unwrap();
assert_eq!(data_left, expected);
}
#[test]
fn decode_from_read_into_roaring_diff() {
use super::decode_from_read_into_roaring;
use super::MergeOp;
use std::io::Cursor;
use roaring::RoaringTreemap;
let data_right: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 229, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 9, 34, 113, 204, 76, 13, 45, 13, 140, 249, 145, 68, 204, 77, 77, 140, 121, 145, 245, 154, 49, 178, 50, 48, 50, 49, 179, 0, 0, 22, 232, 102, 239, 83, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let mut data: Cursor<Vec<u8>> = Cursor::new(data_right);
let mut data_left = RoaringTreemap::new();
data_left.insert(0);
data_left.insert(2);
data_left.insert(3);
data_left.insert(4);
data_left.insert(5);
data_left.insert(6);
data_left.insert(7);
let mut expected = RoaringTreemap::new();
expected.insert(3);
expected.insert(6);
decode_from_read_into_roaring(&mut data, &MergeOp::Diff, &mut data_left).unwrap();
assert_eq!(data_left, expected);
}
#[test]
fn merge_from_read_to_write() {
use crate::compression::MetadataCompression;
use super::EncodeOpts;
use super::merge_from_read_to_write;
use super::MergeOp;
use std::io::Cursor;
let expected_bytes: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 38, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 229, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 9, 34, 113, 204, 76, 13, 45, 13, 140, 249, 145, 68, 204, 77, 77, 140, 121, 145, 245, 154, 49, 178, 50, 48, 50, 49, 179, 0, 0, 22, 232, 102, 239, 83, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 102, 6, 1, 48, 205, 196, 192, 194, 192, 206, 0, 0, 248, 98, 40, 178, 24, 0, 0, 0];
let data_bytes_1: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 229, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 9, 34, 113, 204, 76, 13, 45, 13, 140, 249, 145, 68, 204, 77, 77, 140, 121, 145, 245, 154, 49, 178, 50, 48, 50, 49, 179, 0, 0, 22, 232, 102, 239, 83, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let data_bytes_2: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 38, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 229, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 9, 34, 113, 204, 76, 13, 45, 13, 140, 249, 145, 68, 204, 77, 77, 140, 121, 145, 245, 154, 49, 178, 50, 48, 50, 49, 179, 0, 0, 22, 232, 102, 239, 83, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 102, 6, 1, 48, 205, 196, 192, 194, 192, 206, 0, 0, 248, 98, 40, 178, 24, 0, 0, 0];
let data_bytes_3: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 3, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 42, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 100, 229, 113, 13, 10, 50, 49, 48, 54, 53, 52, 50, 211, 51, 68, 230, 24, 9, 34, 113, 204, 76, 13, 45, 13, 140, 249, 145, 68, 204, 77, 77, 140, 121, 145, 245, 154, 49, 178, 50, 48, 50, 49, 179, 0, 0, 22, 232, 102, 239, 83, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 86, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 192, 201, 0, 0, 110, 28, 86, 94, 28, 0, 0, 0];
let mut data: Vec<Cursor<Vec<u8>>> = vec![
Cursor::new(data_bytes_1),
Cursor::new(data_bytes_2),
Cursor::new(data_bytes_3)
];
let mut opts = EncodeOpts::default();
opts.encode_query_names = true;
opts.rename_queries = false;
opts.metadata_compression = MetadataCompression::Flate2;
let mut got: Cursor<Vec<u8>> = Cursor::new(Vec::new());
merge_from_read_to_write(&mut data, &mut got, &MergeOp::Intersection, opts).unwrap();
assert_eq!(expected_bytes, *got.get_ref());
}
#[test]
fn merge_from_read_to_write_without_query_names() {
use crate::compression::MetadataCompression;
use super::EncodeOpts;
use super::merge_from_read_to_write;
use super::MergeOp;
use std::io::Cursor;
let expected_bytes: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 96, 100, 101, 96, 100, 98, 102, 1, 0, 191, 97, 224, 4, 8, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 38, 6, 1, 40, 205, 194, 0, 0, 207, 21, 220, 40, 22, 0, 0, 0];
let data_bytes_1: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 96, 100, 101, 96, 100, 98, 102, 1, 0, 191, 97, 224, 4, 8, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 206, 0, 0, 47, 109, 177, 38, 26, 0, 0, 0];
let data_bytes_2: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 96, 100, 101, 96, 100, 98, 102, 1, 0, 191, 97, 224, 4, 8, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 22, 6, 1, 48, 205, 196, 192, 194, 192, 202, 192, 198, 0, 0, 110, 92, 170, 63, 26, 0, 0, 0];
let data_bytes_3: Vec<u8> = vec![97, 104, 100, 97, 0, 0, 0, 1, 2, 0, 2, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1, 0, 51, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 227, 114, 13, 10, 50, 49, 48, 54, 53, 52, 50, 99, 226, 76, 206, 40, 210, 75, 75, 44, 46, 73, 228, 45, 200, 73, 44, 206, 205, 76, 129, 240, 0, 66, 30, 44, 81, 36, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 38, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 99, 96, 100, 101, 96, 100, 98, 102, 1, 0, 191, 97, 224, 4, 8, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 179, 50, 96, 96, 96, 100, 0, 1, 102, 6, 1, 48, 205, 196, 192, 194, 192, 206, 0, 0, 248, 98, 40, 178, 24, 0, 0, 0];
let mut data: Vec<Cursor<Vec<u8>>> = vec![
Cursor::new(data_bytes_1),
Cursor::new(data_bytes_2),
Cursor::new(data_bytes_3)
];
let mut opts = EncodeOpts::default();
opts.encode_query_names = false;
opts.rename_queries = false;
opts.metadata_compression = MetadataCompression::Flate2;
opts.accession = "ERR4035126".as_bytes().to_vec();
let mut got: Cursor<Vec<u8>> = Cursor::new(Vec::new());
merge_from_read_to_write(&mut data, &mut got, &MergeOp::Intersection, opts).unwrap();
assert_eq!(expected_bytes, *got.get_ref());
}
}