noodles_bgzf/gzi/
index.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
use std::io;

use crate::VirtualPosition;

/// A gzip index (GZI).
///
/// A gzip index holds compressed-uncompressed position pairs.
///
/// Like this physical index, this does _not_ include the position of the first block, which is
/// implicity at 0.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Index(Vec<(u64, u64)>);

impl Index {
    /// Returns the virtual position at the given uncompressed position.
    ///
    /// # Examples
    ///
    /// ```
    /// use noodles_bgzf::{self as bgzf, gzi};
    ///
    /// let index = gzi::Index::default();
    /// assert_eq!(index.query(0)?, bgzf::VirtualPosition::default());
    ///
    /// let index = gzi::Index::from(vec![(8, 21), (13, 55)]);
    /// assert_eq!(index.query(0)?, bgzf::VirtualPosition::default());
    /// assert_eq!(index.query(13)?, bgzf::VirtualPosition::try_from((0, 13))?);
    /// assert_eq!(index.query(34)?, bgzf::VirtualPosition::try_from((8, 13))?);
    /// assert_eq!(index.query(89)?, bgzf::VirtualPosition::try_from((13, 34))?);
    /// Ok::<_, Box<dyn std::error::Error>>(())
    /// ```
    pub fn query(&self, pos: u64) -> io::Result<VirtualPosition> {
        let i = self.0.partition_point(|r| r.1 <= pos);

        let (compressed_pos, uncompressed_pos) = if i == 0 { (0, 0) } else { self.0[i - 1] };

        let block_data_pos = u16::try_from(pos - uncompressed_pos)
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;

        VirtualPosition::try_from((compressed_pos, block_data_pos))
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
    }
}

impl AsRef<[(u64, u64)]> for Index {
    fn as_ref(&self) -> &[(u64, u64)] {
        &self.0
    }
}

impl From<Vec<(u64, u64)>> for Index {
    fn from(index: Vec<(u64, u64)>) -> Self {
        Self(index)
    }
}