Skip to content

Commit

Permalink
bgzf/async/reader: Add seeking to an uncompressed position
Browse files Browse the repository at this point in the history
Closes #273.
  • Loading branch information
zaeleus committed Jun 27, 2024
1 parent fa63f11 commit 4fbad66
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 1 deletion.
9 changes: 9 additions & 0 deletions noodles-bgzf/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## Unreleased

### Added

* bgzf/async/reader: Add seeking to an uncompressed position
(`Reader::seek_by_uncompressed_position`) ([#273]).

[#273]: https://github.com/zaeleus/noodles/issues/273

## 0.31.0 - 2024-06-17

### Added
Expand Down
44 changes: 43 additions & 1 deletion noodles-bgzf/src/async/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use tokio::io::{AsyncBufRead, AsyncRead, AsyncSeek, ReadBuf};

pub use self::builder::Builder;
use self::inflater::Inflater;
use crate::{Block, VirtualPosition};
use crate::{gzi, Block, VirtualPosition};

pin_project! {
/// An async BGZF reader.
Expand Down Expand Up @@ -175,6 +175,48 @@ where

Ok(pos)
}

/// Seeks the stream to the given uncompressed position.
///
/// # Examples
///
/// ```
/// # use std::io::Cursor;
///
/// # #[tokio::main]
/// # async fn main() -> tokio::io::Result<()> {
/// use noodles_bgzf as bgzf;
/// use tokio::io;
///
/// let mut reader = bgzf::AsyncReader::new(Cursor::new(Vec::new()));
///
/// let index = vec![(0, 0)];
/// reader.seek_by_uncompressed_position(&index, 0).await?;
/// # Ok(())
/// # }
/// ```
pub async fn seek_by_uncompressed_position(
&mut self,
index: &gzi::Index,
pos: u64,
) -> io::Result<u64> {
assert!(!index.is_empty());

let i = index.partition_point(|r| r.1 <= pos);
// SAFETY: `i` is > 0.
let record = index[i - 1];

let cpos = record.0;
let upos = u16::try_from(pos - record.1)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;

let virtual_position = VirtualPosition::try_from((cpos, upos))
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;

self.seek(virtual_position).await?;

Ok(pos)
}
}

impl<R> AsyncRead for Reader<R>
Expand Down

0 comments on commit 4fbad66

Please sign in to comment.