1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/// Three items of information may need to be transferred in a
/// Block (Block1 or Block2) option:
/// * the size of the block ([`Block::size`])
/// * whether more blocks are following ([`Block::more`])
/// * the relative number of the block ([`Block::num`]) within a sequence of blocks with the given size.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Block(u32);

impl Block {
  #[allow(missing_docs)]
  pub fn new(size: u16, num: u32, more: bool) -> Self {
    let num = num << 4;
    let more = u32::from(more) << 3;
    let size = f32::from(size).log2() as u32 - 4;

    Self(num | more | size)
  }

  #[allow(missing_docs)]
  pub fn size(&self) -> u16 {
    let szx = (self.0 & 0b111).min(6);
    2u16.pow(szx + 4)
  }

  #[allow(missing_docs)]
  pub fn more(&self) -> bool {
    (self.0 & 0b1000) >> 3 == 1
  }

  #[allow(missing_docs)]
  pub fn num(&self) -> u32 {
    self.0 >> 4
  }
}

impl From<Block> for u32 {
  fn from(b: Block) -> Self {
    b.0
  }
}

#[cfg(test)]
mod test {
  use super::*;

  #[test]
  fn block() {
    let b = Block(33);
    assert_eq!(b.size(), 32);
    assert_eq!(b.num(), 2);
    assert_eq!(b.more(), false);

    let b = Block(59);
    assert_eq!(b.size(), 128);
    assert_eq!(b.num(), 3);
    assert_eq!(b.more(), true);

    assert_eq!(Block::new(32, 2, false), Block(33));
    assert_eq!(Block::new(128, 3, true), Block(59));
  }
}