noodles_bam/io/reader/header/reference_sequences/
reference_sequence.rs1use 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, 0x73, 0x71, 0x30, 0x00, 0x08, 0x00, 0x00, 0x00, ];
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, 0x73, 0x71, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, ];
74 assert!(matches!(
75 read_reference_sequence(&mut &src[..]),
76 Err(e) if e.kind() == io::ErrorKind::InvalidData
77 ));
78
79 Ok(())
80 }
81}