sview_fmindex/
load_from_blob.rs

1use crate::{
2    FmIndex,
3    // traits
4    Position, Block,
5    components::{
6        Header, View,
7        // headers
8        MagicNumber, TextEncoder, CountArrayHeader, SuffixArrayHeader, BwmHeader,
9        // views
10        CountArrayView, SuffixArrayView, BwmView,
11    },
12};
13
14/// Error type for loading fm-index from blob
15#[derive(Debug, thiserror::Error)]
16pub enum LoadError {
17    /// The provided data does not appear to be a valid FM-index blob, often due to a magic number mismatch or corruption.
18    #[error("Invalid FM-index format. The data does not appear to be a valid FM-index blob.")]
19    InvalidFormat,
20
21    /// The size of the provided blob does not match the expected size calculated from its headers.
22    #[error("Mismatched blob size: headers indicate a total size of {0} bytes, but the provided blob is {1} bytes.")]
23    MismatchedBlobSize(usize, usize),
24}
25
26
27impl<'a, P: Position, B: Block, E: TextEncoder> FmIndex<'a, P, B, E> {
28    /// Load fm-index from blob
29    pub fn load(blob: &'a [u8]) -> Result<Self, LoadError> {
30        // Load headers
31        let (magic_number, remaining_bytes) = MagicNumber::read_from_blob::<B>(blob);
32        if !(magic_number.is_valid() && magic_number.is_supported_version()) {
33            return Err(LoadError::InvalidFormat);
34        }
35        let (text_encoder, remaining_bytes) = E::read_from_blob::<B>(remaining_bytes);
36        let (count_array_header, remaining_bytes) = CountArrayHeader::read_from_blob::<B>(remaining_bytes);
37        let (suffix_array_header, remaining_bytes) = SuffixArrayHeader::read_from_blob::<B>(remaining_bytes);
38        let (bwm_header, body_blob) = BwmHeader::read_from_blob::<B>(remaining_bytes);
39
40        // check body size
41        let actual_body_size = body_blob.len();
42        let expected_body_size = {
43            CountArrayView::<P>::aligned_body_size::<B>(&count_array_header)
44            + SuffixArrayView::<P>::aligned_body_size::<B>(&suffix_array_header)
45            + BwmView::<P, B>::aligned_body_size::<B>(&bwm_header)
46        };
47        if actual_body_size != expected_body_size {
48            let header_size = {
49                magic_number.aligned_size::<B>()
50                + text_encoder.aligned_size::<B>()
51                + count_array_header.aligned_size::<B>()
52                + suffix_array_header.aligned_size::<B>()
53                + bwm_header.aligned_size::<B>()
54            };
55            return Err(LoadError::MismatchedBlobSize(
56                header_size + expected_body_size,
57                header_size + actual_body_size,
58            ));
59        }
60
61        // Get views
62        //  - Count array
63        let mut body_start_index = 0;
64        let mut body_end_index = CountArrayView::<P>::aligned_body_size::<B>(&count_array_header);
65        let count_array_view = CountArrayView::<P>::load_from_body::<B>(&count_array_header, &body_blob[body_start_index..body_end_index]);
66        //  - Suffix array
67        body_start_index = body_end_index;
68        body_end_index += SuffixArrayView::<P>::aligned_body_size::<B>(&suffix_array_header);
69        let suffix_array_view = SuffixArrayView::<P>::load_from_body::<B>(&suffix_array_header, &body_blob[body_start_index..body_end_index]);
70        //  - BWM
71        body_start_index = body_end_index;
72        body_end_index += BwmView::<P, B>::aligned_body_size::<B>(&bwm_header);
73        let bwm_view = BwmView::<P, B>::load_from_body::<B>(&bwm_header, &body_blob[body_start_index..body_end_index]);
74
75        Ok(Self {
76            source_blob: blob,
77            magic_number,
78            text_encoder,
79            count_array_header,
80            suffix_array_header,
81            bwm_header,
82            count_array_view,
83            suffix_array_view,
84            bwm_view,
85        })
86    }
87}