noodles_bam/io/reader/header/reference_sequences/
reference_sequence.rs

1use std::{
2    io::{self, Read},
3    num::NonZero,
4};
5
6use bstr::BString;
7use noodles_sam::header::record::value::{Map, map::ReferenceSequence};
8
9use crate::io::reader::{bytes_with_nul_to_bstring, num::read_u32_le};
10
11pub(super) fn read_reference_sequence<R>(
12    reader: &mut R,
13) -> io::Result<(BString, Map<ReferenceSequence>)>
14where
15    R: Read,
16{
17    let name = read_name(reader)?;
18
19    let len = read_length(reader)?;
20    let reference_sequence = Map::<ReferenceSequence>::new(len);
21
22    Ok((name, reference_sequence))
23}
24
25fn read_name<R>(reader: &mut R) -> io::Result<BString>
26where
27    R: Read,
28{
29    let l_name = read_u32_le(reader).and_then(|n| {
30        usize::try_from(n).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
31    })?;
32
33    let mut c_name = vec![0; l_name];
34    reader.read_exact(&mut c_name)?;
35
36    bytes_with_nul_to_bstring(&c_name)
37}
38
39fn read_length<R>(reader: &mut R) -> io::Result<NonZero<usize>>
40where
41    R: Read,
42{
43    read_u32_le(reader).and_then(|len| {
44        usize::try_from(len)
45            .and_then(NonZero::try_from)
46            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
47    })
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    #[test]
55    fn test_read_reference_sequence() -> Result<(), Box<dyn std::error::Error>> {
56        let src = [
57            0x04, 0x00, 0x00, 0x00, // l_name = 4
58            0x73, 0x71, 0x30, 0x00, // name = "sq0\x00"
59            0x08, 0x00, 0x00, 0x00, // l_ref = 8
60        ];
61
62        let actual = read_reference_sequence(&mut &src[..])?;
63        let expected = (
64            BString::from("sq0"),
65            Map::<ReferenceSequence>::new(const { NonZero::new(8).unwrap() }),
66        );
67        assert_eq!(actual, expected);
68
69        let src = [
70            0x04, 0x00, 0x00, 0x00, // l_name = 4
71            0x73, 0x71, 0x30, 0x00, // name = "sq0\x00"
72            0x00, 0x00, 0x00, 0x00, // l_ref = 0
73        ];
74        assert!(matches!(
75            read_reference_sequence(&mut &src[..]),
76            Err(e) if e.kind() == io::ErrorKind::InvalidData
77        ));
78
79        Ok(())
80    }
81}