-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
261 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
//! Async FASTA I/O. | ||
|
||
pub(crate) mod reader; | ||
mod writer; | ||
|
||
pub use self::reader::Reader; | ||
pub use self::{reader::Reader, writer::Writer}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
//! Async FASTA writer. | ||
|
||
mod record; | ||
|
||
use tokio::io::{self, AsyncWrite}; | ||
|
||
use self::record::write_record; | ||
use crate::Record; | ||
|
||
/// An async FASTA writer. | ||
pub struct Writer<W> { | ||
inner: W, | ||
} | ||
|
||
impl<W> Writer<W> { | ||
/// Returns a reference to the underlying writer. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// use noodles_fasta as fasta; | ||
/// use tokio::io; | ||
/// let writer = fasta::r#async::io::Writer::new(io::sink()); | ||
/// let _inner = writer.get_ref(); | ||
/// ``` | ||
pub fn get_ref(&self) -> &W { | ||
&self.inner | ||
} | ||
|
||
/// Returns a mutable reference to the underlying writer. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// use noodles_fasta as fasta; | ||
/// use tokio::io; | ||
/// let mut writer = fasta::r#async::io::Writer::new(io::sink()); | ||
/// let _inner = writer.get_mut(); | ||
/// ``` | ||
pub fn get_mut(&mut self) -> &mut W { | ||
&mut self.inner | ||
} | ||
|
||
/// Unwraps and returns the underlying writer. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// use noodles_fasta as fasta; | ||
/// use tokio::io; | ||
/// let writer = fasta::r#async::io::Writer::new(io::sink()); | ||
/// let _inner = writer.into_inner(); | ||
/// ``` | ||
pub fn into_inner(self) -> W { | ||
self.inner | ||
} | ||
} | ||
|
||
impl<W> Writer<W> | ||
where | ||
W: AsyncWrite + Unpin, | ||
{ | ||
/// Creates a FASTA writer. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// use noodles_fasta as fasta; | ||
/// use tokio::io; | ||
/// let writer = fasta::r#async::io::Writer::new(io::sink()); | ||
/// ``` | ||
pub fn new(inner: W) -> Self { | ||
Self { inner } | ||
} | ||
|
||
/// Writes a FASTA record. | ||
/// | ||
/// Sequence lines are hard wrapped at 80 bases. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ``` | ||
/// # #[tokio::main] | ||
/// # async fn main() -> tokio::io::Result<()> { | ||
/// use noodles_fasta::{self as fasta, record::{Definition, Sequence}}; | ||
/// use tokio::io; | ||
/// | ||
/// let mut writer = fasta::r#async::io::Writer::new(io::sink()); | ||
/// | ||
/// let definition = Definition::new("sq0", None); | ||
/// let sequence = Sequence::from(b"ACGT".to_vec()); | ||
/// let record = fasta::Record::new(definition, sequence); | ||
/// | ||
/// writer.write_record(&record).await?; | ||
/// # Ok(()) | ||
/// # } | ||
/// ``` | ||
pub async fn write_record(&mut self, record: &Record) -> io::Result<()> { | ||
write_record(&mut self.inner, record).await | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
mod definition; | ||
mod sequence; | ||
|
||
use tokio::io::{self, AsyncWrite, AsyncWriteExt}; | ||
|
||
use self::{definition::write_definition, sequence::write_sequence}; | ||
use crate::Record; | ||
|
||
const LINE_BASES: usize = 80; | ||
|
||
pub(super) async fn write_record<W>(writer: &mut W, record: &Record) -> io::Result<()> | ||
where | ||
W: AsyncWrite + Unpin, | ||
{ | ||
write_definition(writer, record.definition()).await?; | ||
write_newline(writer).await?; | ||
|
||
write_sequence(writer, record.sequence(), LINE_BASES).await?; | ||
|
||
Ok(()) | ||
} | ||
|
||
async fn write_newline<W>(writer: &mut W) -> io::Result<()> | ||
where | ||
W: AsyncWrite + Unpin, | ||
{ | ||
const LINE_FEED: u8 = b'\n'; | ||
writer.write_all(&[LINE_FEED]).await | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
use tokio::io::{self, AsyncWrite, AsyncWriteExt}; | ||
|
||
use crate::record::Definition; | ||
|
||
pub(super) async fn write_definition<W>(writer: &mut W, definition: &Definition) -> io::Result<()> | ||
where | ||
W: AsyncWrite + Unpin, | ||
{ | ||
write_prefix(writer).await?; | ||
write_name(writer, definition.name()).await?; | ||
|
||
if let Some(description) = definition.description() { | ||
write_separator(writer).await?; | ||
write_description(writer, description).await?; | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
async fn write_prefix<W>(writer: &mut W) -> io::Result<()> | ||
where | ||
W: AsyncWrite + Unpin, | ||
{ | ||
const PREFIX: u8 = b'>'; | ||
writer.write_all(&[PREFIX]).await | ||
} | ||
|
||
async fn write_name<W>(writer: &mut W, name: &[u8]) -> io::Result<()> | ||
where | ||
W: AsyncWrite + Unpin, | ||
{ | ||
writer.write_all(name).await | ||
} | ||
|
||
async fn write_separator<W>(writer: &mut W) -> io::Result<()> | ||
where | ||
W: AsyncWrite + Unpin, | ||
{ | ||
const SEPARATOR: u8 = b' '; | ||
writer.write_all(&[SEPARATOR]).await | ||
} | ||
|
||
async fn write_description<W>(writer: &mut W, description: &[u8]) -> io::Result<()> | ||
where | ||
W: AsyncWrite + Unpin, | ||
{ | ||
writer.write_all(description).await | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[tokio::test] | ||
async fn test_write_definition() -> io::Result<()> { | ||
async fn t(buf: &mut Vec<u8>, definition: &Definition, expected: &[u8]) -> io::Result<()> { | ||
buf.clear(); | ||
write_definition(buf, definition).await?; | ||
assert_eq!(buf, expected); | ||
Ok(()) | ||
} | ||
|
||
let mut buf = Vec::new(); | ||
|
||
t(&mut buf, &Definition::new("sq0", None), b">sq0").await?; | ||
t( | ||
&mut buf, | ||
&Definition::new("sq0", Some(Vec::from("LN:8"))), | ||
b">sq0 LN:8", | ||
) | ||
.await?; | ||
|
||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
use tokio::io::{self, AsyncWrite, AsyncWriteExt}; | ||
|
||
use super::write_newline; | ||
use crate::record::Sequence; | ||
|
||
pub(super) async fn write_sequence<W>( | ||
writer: &mut W, | ||
sequence: &Sequence, | ||
line_bases: usize, | ||
) -> io::Result<()> | ||
where | ||
W: AsyncWrite + Unpin, | ||
{ | ||
for bases in sequence.as_ref().chunks(line_bases) { | ||
writer.write_all(bases).await?; | ||
write_newline(writer).await?; | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[tokio::test] | ||
async fn test_write_sequence() -> io::Result<()> { | ||
let mut writer = Vec::new(); | ||
let sequence = Sequence::from(b"AC".to_vec()); | ||
write_sequence(&mut writer, &sequence, 4).await?; | ||
assert_eq!(writer, b"AC\n"); | ||
|
||
writer.clear(); | ||
let sequence = Sequence::from(b"ACGT".to_vec()); | ||
write_sequence(&mut writer, &sequence, 4).await?; | ||
assert_eq!(writer, b"ACGT\n"); | ||
|
||
writer.clear(); | ||
let sequence = Sequence::from(b"ACGTACGT".to_vec()); | ||
write_sequence(&mut writer, &sequence, 4).await?; | ||
assert_eq!(writer, b"ACGT\nACGT\n"); | ||
|
||
writer.clear(); | ||
let sequence = Sequence::from(b"ACGTACGTAC".to_vec()); | ||
write_sequence(&mut writer, &sequence, 4).await?; | ||
assert_eq!(writer, b"ACGT\nACGT\nAC\n"); | ||
|
||
Ok(()) | ||
} | ||
} |