blkar_lib/sbx_block/
mod.rs

1#![allow(dead_code)]
2mod crc;
3mod header;
4mod header_tests;
5mod metadata;
6mod metadata_tests;
7mod tests;
8
9pub use self::header::Header;
10pub use self::metadata::make_distribution_string;
11pub use self::metadata::make_too_much_meta_err_string;
12pub use self::metadata::Metadata;
13pub use self::metadata::MetadataID;
14
15use smallvec::SmallVec;
16
17pub fn meta_to_meta_id(meta: &Metadata) -> MetadataID {
18    self::metadata::meta_to_id(meta)
19}
20
21pub fn meta_id_to_str(id: MetadataID) -> &'static str {
22    self::metadata::id_to_str(id)
23}
24
25pub fn get_meta_ref_by_meta_id(metas: &[Metadata], id: MetadataID) -> Option<&Metadata> {
26    self::metadata::get_meta_ref_by_id(metas, id)
27}
28
29pub fn get_meta_ref_mut_by_meta_id(
30    metas: &mut [Metadata],
31    id: MetadataID,
32) -> Option<&mut Metadata> {
33    self::metadata::get_meta_ref_mut_by_id(metas, id)
34}
35
36use self::crc::*;
37use crate::sbx_specs::{
38    ver_to_block_size, ver_to_data_size, ver_uses_rs, Version, SBX_FILE_UID_LEN,
39    SBX_FIRST_DATA_SEQ_NUM, SBX_HEADER_SIZE,
40};
41
42use crate::multihash;
43
44macro_rules! make_meta_getter {
45    (
46        $func_name:ident => $meta_id:ident => ret_ref $ret_type:ty
47    ) => {
48        #[allow(non_snake_case)]
49        pub fn $func_name (&self) -> Result<Option<&$ret_type>, Error> {
50            match self.get_meta_ref_by_id(MetadataID::$meta_id)? {
51                None                        => Ok(None),
52                Some(Metadata::$meta_id(x)) => Ok(Some(x)),
53                _                           => unreachable!(),
54            }
55        }
56    };
57    (
58        $func_name:ident => $meta_id:ident => ret_val $ret_type:ty
59    ) => {
60        #[allow(non_snake_case)]
61        pub fn $func_name (&self) -> Result<Option<$ret_type>, Error> {
62            match self.get_meta_ref_by_id(MetadataID::$meta_id)? {
63                None                         => Ok(None),
64                Some(&Metadata::$meta_id(x)) => Ok(Some(x)),
65                _                            => panic!(),
66            }
67        }
68    };
69}
70
71macro_rules! check_ver_consistent_with_opt {
72    (
73        $version:expr, $val:expr
74    ) => {{
75        match $val {
76            None => assert!(!ver_uses_rs($version)),
77            Some(_) => assert!(ver_uses_rs($version)),
78        }
79    }};
80}
81
82#[derive(Clone, Copy, Debug, PartialEq)]
83pub enum BlockType {
84    Data,
85    Meta,
86}
87
88#[derive(Clone, Debug, PartialEq)]
89pub enum Error {
90    IncorrectBlockType,
91    IncorrectBufferSize,
92    TooMuchMetadata(Vec<Metadata>),
93    InvalidCRC,
94    SeqNumOverflow,
95    ParseError,
96    FailedPred,
97}
98
99#[derive(Clone, Debug, PartialEq)]
100pub enum Data {
101    Data,
102    Meta(Vec<Metadata>),
103}
104
105#[derive(Clone, Debug, PartialEq)]
106pub struct Block {
107    header: Header,
108    data: Data,
109}
110
111macro_rules! slice_buf {
112    (
113        whole => $self:ident, $buf:ident
114    ) => {
115        &$buf[..block_size!($self)]
116    };
117    (
118        whole_mut => $self:ident, $buf:ident
119    ) => {
120        &mut $buf[..block_size!($self)]
121    };
122    (
123        header => $self:ident, $buf:ident
124    ) => {
125        &$buf[..SBX_HEADER_SIZE]
126    };
127    (
128        header_mut => $self:ident, $buf:ident
129    ) => {
130        &mut $buf[..SBX_HEADER_SIZE]
131    };
132    (
133        data => $self:ident, $buf:ident
134    ) => {
135        &$buf[SBX_HEADER_SIZE..block_size!($self)]
136    };
137    (
138        data_mut => $self:ident, $buf:ident
139    ) => {
140        &mut $buf[SBX_HEADER_SIZE..block_size!($self)]
141    };
142}
143
144macro_rules! check_buffer {
145    (
146        $self:ident, $buf:ident
147    ) => {
148        if $buf.len() < block_size!($self) {
149            panic!("Insufficient buffer size");
150        }
151    };
152}
153
154macro_rules! block_size {
155    (
156        $self:ident
157    ) => {
158        ver_to_block_size($self.header.version)
159    };
160}
161
162/*macro_rules! data_size {
163    (
164        $self:ident
165    ) => {
166        ver_to_data_size($self.header.version)
167    }
168}*/
169
170pub fn write_padding(version: Version, skip: usize, buffer: &mut [u8]) -> usize {
171    let block_size = ver_to_block_size(version);
172    let start = SBX_HEADER_SIZE + skip;
173
174    for i in start..block_size {
175        buffer[i] = 0x1A;
176    }
177
178    block_size - start
179}
180
181pub fn slice_buf(version: Version, buffer: &[u8]) -> &[u8] {
182    &buffer[..ver_to_block_size(version)]
183}
184
185pub fn slice_buf_mut(version: Version, buffer: &mut [u8]) -> &mut [u8] {
186    &mut buffer[..ver_to_block_size(version)]
187}
188
189pub fn slice_header_buf(buffer: &[u8]) -> &[u8] {
190    &buffer[..SBX_HEADER_SIZE]
191}
192
193pub fn slice_header_buf_mut(buffer: &mut [u8]) -> &mut [u8] {
194    &mut buffer[..SBX_HEADER_SIZE]
195}
196
197pub fn slice_data_buf(version: Version, buffer: &[u8]) -> &[u8] {
198    &buffer[SBX_HEADER_SIZE..ver_to_block_size(version)]
199}
200
201pub fn slice_data_buf_mut(version: Version, buffer: &mut [u8]) -> &mut [u8] {
202    &mut buffer[SBX_HEADER_SIZE..ver_to_block_size(version)]
203}
204
205pub fn check_if_buffer_valid(buffer: &[u8]) -> bool {
206    let mut block = Block::new(Version::V1, b"\x00\x00\x00\x00\x00\x00", BlockType::Data);
207
208    match block.sync_from_buffer(buffer, None, None) {
209        Ok(()) => {}
210        Err(_) => {
211            return false;
212        }
213    }
214
215    block.verify_crc(buffer).unwrap()
216}
217
218pub fn seq_num_is_meta(seq_num: u32) -> bool {
219    seq_num == 0
220}
221
222pub fn seq_num_is_parity(seq_num: u32, data_shards: usize, parity_shards: usize) -> bool {
223    if seq_num == 0 {
224        false // this is metadata block
225    } else {
226        // data sets
227        let index = seq_num - SBX_FIRST_DATA_SEQ_NUM as u32;
228        let index_in_set = index % (data_shards + parity_shards) as u32;
229
230        (data_shards as u32 <= index_in_set)
231    }
232}
233
234pub fn seq_num_is_parity_w_data_par_burst(
235    seq_num: u32,
236    data_par_burst: Option<(usize, usize, usize)>,
237) -> bool {
238    match data_par_burst {
239        Some((data, parity, _)) => seq_num_is_parity(seq_num, data, parity),
240        None => false,
241    }
242}
243
244pub fn calc_meta_block_dup_write_pos_s(
245    version: Version,
246    data_par_burst: Option<(usize, usize, usize)>,
247) -> SmallVec<[u64; 32]> {
248    check_ver_consistent_with_opt!(version, data_par_burst);
249
250    let block_size = ver_to_block_size(version) as u64;
251
252    let mut res = calc_meta_block_dup_write_indices(data_par_burst);
253
254    for i in res.iter_mut() {
255        *i = *i * block_size;
256    }
257
258    res
259}
260
261pub fn calc_meta_block_dup_write_indices(
262    data_par_burst: Option<(usize, usize, usize)>,
263) -> SmallVec<[u64; 32]> {
264    match data_par_burst {
265        Some((_, parity, burst)) => {
266            let mut res: SmallVec<[u64; 32]> = SmallVec::with_capacity(1 + parity);
267
268            for i in 1..1 + parity as u64 {
269                res.push(i * (1 + burst) as u64);
270            }
271
272            res
273        }
274        None => SmallVec::new(),
275    }
276}
277
278pub fn calc_meta_block_all_write_pos_s(
279    version: Version,
280    data_par_burst: Option<(usize, usize, usize)>,
281) -> SmallVec<[u64; 32]> {
282    let mut res = calc_meta_block_dup_write_pos_s(version, data_par_burst);
283
284    res.push(0);
285
286    res.sort();
287
288    res
289}
290
291pub fn calc_meta_block_all_write_indices(
292    data_par_burst: Option<(usize, usize, usize)>,
293) -> SmallVec<[u64; 32]> {
294    let mut res = calc_meta_block_dup_write_indices(data_par_burst);
295
296    res.push(0);
297
298    res.sort();
299
300    res
301}
302
303pub fn calc_data_block_write_pos(
304    version: Version,
305    seq_num: u32,
306    meta_enabled: Option<bool>,
307    data_par_burst: Option<(usize, usize, usize)>,
308) -> u64 {
309    check_ver_consistent_with_opt!(version, data_par_burst);
310
311    let block_size = ver_to_block_size(version) as u64;
312
313    calc_data_block_write_index(seq_num, meta_enabled, data_par_burst) * block_size
314}
315
316pub fn calc_data_block_write_index(
317    seq_num: u32,
318    meta_enabled: Option<bool>,
319    data_par_burst: Option<(usize, usize, usize)>,
320) -> u64 {
321    // the following transforms seq num to data index
322    // then do the transformation based on data index
323    assert!(seq_num >= SBX_FIRST_DATA_SEQ_NUM);
324
325    // calculate the sequential data index
326    let index = (seq_num - SBX_FIRST_DATA_SEQ_NUM) as u64;
327
328    match data_par_burst {
329        None => {
330            let meta_enabled = meta_enabled.unwrap_or(true);
331
332            if meta_enabled {
333                SBX_FIRST_DATA_SEQ_NUM as u64 + index
334            } else {
335                index
336            }
337        }
338        Some((data, parity, burst)) => {
339            shadow_to_avoid_use!(meta_enabled);
340
341            if burst == 0 {
342                let meta_block_count = 1 + parity as u64;
343
344                return meta_block_count + index;
345            }
346
347            let data_shards = data as u64;
348            let parity_shards = parity as u64;
349            let burst_err_resistance = burst as u64;
350
351            let super_block_set_size = (data_shards + parity_shards) * burst_err_resistance;
352
353            // sub A block set partitioning deals with the super block set
354            // of the sequential data index arrangement
355            // i.e. sub A = partitioning of input
356            //
357            // sub B block set partitioning deals with the super block set
358            // of the interleaving data index arrangement
359            // i.e. sub B = partitioning of output
360            //
361            // sub A block set partitioning slices at total shards interval
362            // sub B block set partitioning slices at burst resistance level interval
363            let sub_a_block_set_size = data_shards + parity_shards;
364            let sub_b_block_set_size = burst_err_resistance;
365
366            // calculate the index of the start of super block set with
367            // respect to the data index
368            let super_block_set_index = index / super_block_set_size;
369            // calculate index of current seq num inside the current super block set
370            let index_in_super_block_set = index % super_block_set_size;
371
372            // calculate the index of the start of sub A block set inside
373            // the current super block set
374            let sub_a_block_set_index = index_in_super_block_set / sub_a_block_set_size;
375            // calculate index of current seq num inside the current sub A block set
376            let index_in_sub_a_block_set = index_in_super_block_set % sub_a_block_set_size;
377
378            let sub_b_block_set_index = index_in_sub_a_block_set;
379            let index_in_sub_b_block_set = sub_a_block_set_index;
380
381            let new_index_in_super_block_set =
382                sub_b_block_set_index * sub_b_block_set_size + index_in_sub_b_block_set;
383
384            // M = data_shards
385            // N = parity_shards
386            //
387            // calculate the number of metadata blocks before the current
388            // seq num in the interleaving scheme
389            let meta_block_count = if super_block_set_index == 0 {
390                // first super block set
391                // one metadata block at front of first (1 + N) sub B blocks
392                if sub_b_block_set_index < 1 + parity_shards {
393                    1 + sub_b_block_set_index
394                } else {
395                    1 + parity_shards
396                }
397            } else {
398                1 + parity_shards
399            };
400
401            // finally calculate the index in interleaving data index arrangement
402            let new_index =
403            // number of metadata blocks in front of the data block
404                meta_block_count
405
406            // index of start of super block set
407                + (super_block_set_size * super_block_set_index)
408
409            // index inside the super block set
410                + new_index_in_super_block_set;
411
412            new_index
413        }
414    }
415}
416
417pub fn calc_data_chunk_write_index(seq_num: u32, data_par: Option<(usize, usize)>) -> Option<u64> {
418    if seq_num < SBX_FIRST_DATA_SEQ_NUM {
419        None
420    } else {
421        let index = (seq_num - SBX_FIRST_DATA_SEQ_NUM) as u64;
422
423        match data_par {
424            None => Some(index),
425            Some((data, parity)) => {
426                if seq_num_is_parity(seq_num, data, parity) {
427                    None
428                } else {
429                    let block_set_index = index / (data + parity) as u64;
430                    let index_in_block_set = index % (data + parity) as u64;
431
432                    Some(block_set_index * data as u64 + index_in_block_set)
433                }
434            }
435        }
436    }
437}
438
439pub fn calc_data_chunk_write_pos(
440    version: Version,
441    seq_num: u32,
442    data_par: Option<(usize, usize)>,
443) -> Option<u64> {
444    check_ver_consistent_with_opt!(version, data_par);
445
446    let data_size = ver_to_data_size(version);
447
448    match calc_data_chunk_write_index(seq_num, data_par) {
449        None => None,
450        Some(x) => Some(x as u64 * data_size as u64),
451    }
452}
453
454pub fn calc_seq_num_at_index(
455    index: u64,
456    meta_enabled: Option<bool>,
457    data_par_burst: Option<(usize, usize, usize)>,
458) -> u32 {
459    match data_par_burst {
460        None => {
461            let meta_enabled = meta_enabled.unwrap_or(true);
462
463            if meta_enabled {
464                index as u32
465            } else {
466                SBX_FIRST_DATA_SEQ_NUM + index as u32
467            }
468        }
469        Some((data, parity, burst)) => {
470            shadow_to_avoid_use!(meta_enabled);
471
472            // the following essentially reverses the index transformation in
473            // calc_data_block_write_index
474            if burst == 0 {
475                if index < 1 + parity as u64 {
476                    return 0;
477                } else {
478                    let data_index = index - (1 + parity) as u64;
479
480                    return (data_index + 1) as u32;
481                }
482            }
483
484            let data_shards = data as u64;
485            let parity_shards = parity as u64;
486            let burst_err_resistance = burst as u64;
487
488            // handle metadata seq nums first
489            // M = data shards
490            // N = parity_shards
491            // B = burst_err_resistance
492            //
493            // if index is in first 1 + N block set
494            if index < (1 + parity_shards) * (1 + burst_err_resistance)
495            // and index is in front of a sub B block set
496                && index % (1 + burst_err_resistance) == 0
497            {
498                return 0;
499            }
500
501            let meta_block_count =
502            // if index is in first 1 + N block set
503                if index < (1 + parity_shards) * (1 + burst_err_resistance) {
504                    1 + index / (1 + burst_err_resistance)
505                } else {
506                    1 + parity_shards
507                };
508
509            // same block set sizes from `calc_data_block_write_index`
510            let super_block_set_size = (data_shards + parity_shards) * burst_err_resistance;
511
512            let sub_a_block_set_size = data_shards + parity_shards;
513            let sub_b_block_set_size = burst_err_resistance;
514
515            // calculate the transformed data index
516            // not the original sequential data index yet
517            let index_without_meta = index - meta_block_count;
518
519            // reverse the transformation done in `calc_data_block_write_index`
520            let super_block_set_index = index_without_meta / super_block_set_size;
521            let index_in_super_block_set = index_without_meta % super_block_set_size;
522
523            let sub_b_block_set_index = index_in_super_block_set / sub_b_block_set_size;
524            let index_in_sub_b_block_set = index_in_super_block_set % sub_b_block_set_size;
525
526            let sub_a_block_set_index = index_in_sub_b_block_set;
527            let index_in_sub_a_block_set = sub_b_block_set_index;
528
529            let old_index_in_super_block_set =
530                sub_a_block_set_index * sub_a_block_set_size + index_in_sub_a_block_set;
531
532            // calculate the original sequential data index
533            let old_index =
534            // index of start of super block set
535                (super_block_set_size * super_block_set_index)
536
537            // index inside the super block set
538                + old_index_in_super_block_set;
539
540            (old_index as u32) + SBX_FIRST_DATA_SEQ_NUM as u32
541        }
542    }
543}
544
545impl Block {
546    pub fn new(version: Version, uid: &[u8; SBX_FILE_UID_LEN], block_type: BlockType) -> Block {
547        match block_type {
548            BlockType::Data => {
549                let seq_num = SBX_FIRST_DATA_SEQ_NUM as u32;
550                Block {
551                    header: Header::new(version, uid.clone(), seq_num),
552                    data: Data::Data,
553                }
554            }
555            BlockType::Meta => {
556                let seq_num = 0 as u32;
557                Block {
558                    header: Header::new(version, uid.clone(), seq_num),
559                    data: Data::Meta(Vec::with_capacity(10)),
560                }
561            }
562        }
563    }
564
565    pub fn dummy() -> Block {
566        let version = Version::V1;
567        let seq_num = SBX_FIRST_DATA_SEQ_NUM as u32;
568        Block {
569            header: Header::new(version, [0; 6], seq_num),
570            data: Data::Data,
571        }
572    }
573
574    pub fn get_version(&self) -> Version {
575        self.header.version
576    }
577
578    pub fn set_version(&mut self, version: Version) {
579        self.header.version = version;
580    }
581
582    pub fn get_uid(&self) -> [u8; SBX_FILE_UID_LEN] {
583        self.header.uid
584    }
585
586    pub fn set_uid(&mut self, uid: [u8; SBX_FILE_UID_LEN]) {
587        self.header.uid = uid;
588    }
589
590    pub fn get_crc(&self) -> u16 {
591        self.header.crc
592    }
593
594    pub fn get_seq_num(&self) -> u32 {
595        self.header.seq_num
596    }
597
598    pub fn set_seq_num(&mut self, seq_num: u32) {
599        self.header.seq_num = seq_num;
600
601        self.switch_block_type_to_match_header();
602    }
603
604    pub fn add_seq_num(&mut self, val: u32) -> Result<(), Error> {
605        match self.header.seq_num.checked_add(val) {
606            None => {
607                return Err(Error::SeqNumOverflow);
608            }
609            Some(x) => {
610                self.header.seq_num = x;
611            }
612        }
613
614        self.switch_block_type_to_match_header();
615
616        Ok(())
617    }
618
619    pub fn add1_seq_num(&mut self) -> Result<(), Error> {
620        self.add_seq_num(1)
621    }
622
623    pub fn block_type(&self) -> BlockType {
624        match self.data {
625            Data::Data => BlockType::Data,
626            Data::Meta(_) => BlockType::Meta,
627        }
628    }
629
630    pub fn is_meta(&self) -> bool {
631        match self.block_type() {
632            BlockType::Data => false,
633            BlockType::Meta => true,
634        }
635    }
636
637    pub fn is_data(&self) -> bool {
638        match self.block_type() {
639            BlockType::Data => true,
640            BlockType::Meta => false,
641        }
642    }
643
644    pub fn is_parity(&self, data_shards: usize, parity_shards: usize) -> bool {
645        ver_uses_rs(self.header.version)
646            && seq_num_is_parity(self.get_seq_num(), data_shards, parity_shards)
647    }
648
649    pub fn is_parity_w_data_par_burst(
650        &self,
651        data_par_burst: Option<(usize, usize, usize)>,
652    ) -> bool {
653        ver_uses_rs(self.header.version)
654            && seq_num_is_parity_w_data_par_burst(self.get_seq_num(), data_par_burst)
655    }
656
657    pub fn get_meta_ref_by_id(&self, id: MetadataID) -> Result<Option<&Metadata>, Error> {
658        match self.data {
659            Data::Data => Err(Error::IncorrectBlockType),
660            Data::Meta(ref metas) => Ok(metadata::get_meta_ref_by_id(metas, id)),
661        }
662    }
663
664    pub fn get_meta_ref_mut_by_id(
665        &mut self,
666        id: MetadataID,
667    ) -> Result<Option<&mut Metadata>, Error> {
668        match self.data {
669            Data::Data => Err(Error::IncorrectBlockType),
670            Data::Meta(ref mut metas) => Ok(metadata::get_meta_ref_mut_by_id(metas, id)),
671        }
672    }
673
674    make_meta_getter!(get_FNM => FNM => ret_ref str);
675    make_meta_getter!(get_SNM => SNM => ret_ref str);
676    make_meta_getter!(get_FSZ => FSZ => ret_val u64);
677    make_meta_getter!(get_FDT => FDT => ret_val i64);
678    make_meta_getter!(get_SDT => SDT => ret_val i64);
679    make_meta_getter!(get_HSH => HSH => ret_ref multihash::HashBytes);
680    make_meta_getter!(get_RSD => RSD => ret_val u8);
681    make_meta_getter!(get_RSP => RSP => ret_val u8);
682
683    pub fn metas(&self) -> Result<&Vec<Metadata>, Error> {
684        match self.data {
685            Data::Data => Err(Error::IncorrectBlockType),
686            Data::Meta(ref meta) => Ok(meta),
687        }
688    }
689
690    pub fn metas_mut(&mut self) -> Result<&mut Vec<Metadata>, Error> {
691        match self.data {
692            Data::Data => Err(Error::IncorrectBlockType),
693            Data::Meta(ref mut meta) => Ok(meta),
694        }
695    }
696
697    pub fn update_meta(&mut self, m: &Metadata) -> Result<(), Error> {
698        match self.data {
699            Data::Data => Err(Error::IncorrectBlockType),
700            Data::Meta(ref mut metas) => {
701                let id = metadata::meta_to_id(m);
702                let m = m.clone();
703                match metadata::get_meta_ref_mut_by_id(metas, id) {
704                    None => metas.push(m),
705                    Some(x) => *x = m,
706                };
707                Ok(())
708            }
709        }
710    }
711
712    pub fn update_metas(&mut self, ms: &[Metadata]) -> Result<(), Error> {
713        for m in ms {
714            if let Err(e) = self.update_meta(m) {
715                return Err(e);
716            }
717        }
718        Ok(())
719    }
720
721    pub fn remove_metas(&mut self, ids: &[MetadataID]) -> Result<(), Error> {
722        match self.data {
723            Data::Data => Err(Error::IncorrectBlockType),
724            Data::Meta(ref mut metas) => {
725                metas.retain(|m| !ids.contains(&metadata::meta_to_id(m)));
726                Ok(())
727            }
728        }
729    }
730
731    pub fn calc_crc(&self, buffer: &[u8]) -> u16 {
732        check_buffer!(self, buffer);
733
734        let crc = self.header.calc_crc();
735
736        crc_ccitt_generic(crc, slice_buf!(data => self, buffer))
737    }
738
739    pub fn update_crc(&mut self, buffer: &[u8]) {
740        self.header.crc = self.calc_crc(buffer);
741    }
742
743    fn header_type_matches_block_type(&self) -> bool {
744        self.header.header_type() == self.block_type()
745    }
746
747    pub fn sync_to_buffer(
748        &mut self,
749        update_crc: Option<bool>,
750        buffer: &mut [u8],
751    ) -> Result<(), Error> {
752        check_buffer!(self, buffer);
753
754        let update_crc = update_crc.unwrap_or(true);
755
756        match self.data {
757            Data::Meta(ref meta) => {
758                if self.get_seq_num() == 0 {
759                    // not a metadata parity block
760                    // transform metadata to bytes
761                    metadata::to_bytes(meta, slice_buf!(data_mut => self, buffer))?;
762                }
763            }
764            Data::Data => {}
765        }
766
767        match self.block_type() {
768            BlockType::Data => {
769                if update_crc {
770                    self.update_crc(buffer)
771                }
772            }
773            BlockType::Meta => self.update_crc(buffer),
774        }
775
776        self.header.to_bytes(slice_buf!(header_mut => self, buffer));
777
778        Ok(())
779    }
780
781    fn switch_block_type(&mut self) {
782        let block_type = self.block_type();
783
784        if block_type == BlockType::Meta {
785            self.data = Data::Data;
786        } else {
787            self.data = Data::Meta(Vec::with_capacity(10));
788        }
789    }
790
791    fn switch_block_type_to_match_header(&mut self) {
792        if !self.header_type_matches_block_type() {
793            self.switch_block_type();
794        }
795    }
796
797    pub fn sync_from_buffer_header_only(&mut self, buffer: &[u8]) -> Result<(), Error> {
798        self.header.from_bytes(slice_buf!(header => self, buffer))?;
799
800        self.switch_block_type_to_match_header();
801
802        Ok(())
803    }
804
805    pub fn sync_from_buffer(
806        &mut self,
807        buffer: &[u8],
808        header_pred: Option<&dyn Fn(&Header) -> bool>,
809        pred: Option<&dyn Fn(&Block) -> bool>,
810    ) -> Result<(), Error> {
811        self.sync_from_buffer_header_only(buffer)?;
812
813        if let Some(pred) = header_pred {
814            if !pred(&self.header) {
815                return Err(Error::FailedPred);
816            }
817        }
818
819        check_buffer!(self, buffer);
820
821        self.enforce_crc(buffer)?;
822
823        match self.data {
824            Data::Meta(ref mut meta) => {
825                // parse if it is metadata
826                if self.header.seq_num == 0 {
827                    meta.clear();
828                    let res = metadata::from_bytes(slice_buf!(data => self, buffer))?;
829                    for r in res.into_iter() {
830                        meta.push(r);
831                    }
832                }
833            }
834            Data::Data => {}
835        }
836
837        match pred {
838            Some(pred) => {
839                if pred(&self) {
840                    Ok(())
841                } else {
842                    Err(Error::FailedPred)
843                }
844            }
845            None => Ok(()),
846        }
847    }
848
849    pub fn verify_crc(&self, buffer: &[u8]) -> Result<bool, Error> {
850        Ok(self.header.crc == self.calc_crc(buffer))
851    }
852
853    pub fn enforce_crc(&self, buffer: &[u8]) -> Result<(), Error> {
854        if self.verify_crc(buffer)? {
855            Ok(())
856        } else {
857            Err(Error::InvalidCRC)
858        }
859    }
860}