Handling simple blocks

Blocks are the basic components forming a frame. There exist three types of blocks:

  • A raw block contains some data, without any compression, that must be copied while decoding.
  • A RLE block is a block which contains a byte b and a length l. Decoding it duplicates the b byte l times.
  • A compressed block contains much more complex information and is the basis of Zstandard compression capabilities.

For a start, you will implement the decoding of the first two block types.

Structure

✅ In a block module, add an enumerated Block type with two variants (for now): RawBlock which encapsulates a slice, and RLEBlock which contains a byte and a repeat field.

✅ Implement Block::parse() which accepts a &mut ForwardByteParser and returns a result containing a (Block, bool) pair. The bool is true if the block is the last block of the frame.

Do not forget to add a dedicated Error type in the block module, as well as a Result type alias. If the block type is invalid (3 is reserved), a Error::ReservedBlockType should be returned. Also, you can call unimplemented!() if you encounter a block of type 2 (compressed block) as we do not implement it yet.

✅ Implement the Block::decode(self) method which decodes a block (and destroys the Block object by taking self).

Right now, decode() does not need any other parameter. This will no longer be the case when we implement compressed blocks, as decoding a compressed block requires accessing a decoding context containing information about earlier operations. Also, decode() needs to return a Result: even if decoding cannot fail right now, it will later when more complex blocks are implemented.

✅ Add tests.

Here are two simple tests, you must add others, including for checking that errors are correctly detected:

use net7212::block::Block;
use net7212::parsing::ForwardByteParser;

#[test]
fn decode_raw_block_last() {
    let mut parser = ForwardByteParser::new(&[
        // Raw block, last block, len 4, content 0x10, 0x20, 0x30, 0x40,
        // and an extra 0x50 at the end.
        0x21, 0x0, 0x0, 0x10, 0x20, 0x30, 0x40, 0x50
    ]);
    let (block, last) = Block::parse(&mut parser).unwrap();
    assert!(last);
    assert!(matches!(block, Block::RawBlock(&[0x10, 0x20, 0x30, 0x40])));
    assert_eq!(1, parser.len());
    let decoded = block.decode().unwrap();
    assert_eq!(vec![0x10, 0x20, 0x30, 0x40], decoded);
}

#[test]
fn decode_rle_block_not_last() {
    let mut parser = ForwardByteParser::new(&[
        // RLE block, not last, byte 0x42 and repeat 0x30004,
        // and an extra 0x50 at the end.
        0x22, 0x0, 0x18, 0x42, 0x50
    ]);
    let (block, last) = Block::parse(&mut parser).unwrap();
    assert!(!last);
    assert!(matches!(
        block,
        Block::RLEBlock {
            byte: 0x42,
            repeat: 196612
        }
    ));
    assert_eq!(1, parser.len());
    let decoded = block.decode().unwrap();
    assert_eq!(196612, decoded.len());
    assert!(decoded.into_iter().all(|b| b == 0x42));
}