aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/base32.zig66
1 files changed, 53 insertions, 13 deletions
diff --git a/src/base32.zig b/src/base32.zig
index 149e5f0..fa58327 100644
--- a/src/base32.zig
+++ b/src/base32.zig
@@ -29,8 +29,10 @@ pub const Encoder = struct {
29 return dest[0..out_len]; 29 return dest[0..out_len];
30 } 30 }
31 31
32 fn n_front_bits(self: *const Self) u3 { 32 // Calculates the amount of bits can be read from `self.buffer[self.index]`,
33 // bit_off n_front_bits 33 // with a maximum of 5 and an offset of `self.bit_off`.
34 fn frontBitsLen(self: *const Self) u3 {
35 // bit_off frontBitsLen
34 // 0 5 36 // 0 5
35 // 1 5 37 // 1 5
36 // 2 5 38 // 2 5
@@ -42,8 +44,22 @@ pub const Encoder = struct {
42 return if (self.bit_off <= 3) 5 else 7 - self.bit_off + 1; 44 return if (self.bit_off <= 3) 5 else 7 - self.bit_off + 1;
43 } 45 }
44 46
45 fn front(self: *const Self, index: usize) u5 { 47 // Returns the bits of `self.buffer[self.index]`, read with an offset of `self.bit_off`,
46 // bit_off bits shl shr front 48 // aligned to the left of the 5-bit unsigned integer.
49 // Returns null if `self.index` is null.
50 // An illustration of its behaviour, with `self.buffer[self.index]` being 0b10010111:
51 // | `self.bit_off` | `frontBits` |
52 // |----------------|-------------|
53 // | 0 | 0b10010 |
54 // | 1 | 0b00101 |
55 // | 2 | 0b01011 |
56 // | 3 | 0b10111 |
57 // | 4 | 0b01110 |
58 // | 5 | 0b11100 |
59 // | 6 | 0b11000 |
60 // | 7 | 0b10000 |
61 fn frontBits(self: *const Self) ?u5 {
62 // bit_off bitmask shl shr frontBits
47 // 0 0b11111000 3 0b11111 63 // 0 0b11111000 3 0b11111
48 // 1 0b01111100 2 0b11111 64 // 1 0b01111100 2 0b11111
49 // 2 0b00111110 1 0b11111 65 // 2 0b00111110 1 0b11111
@@ -52,33 +68,57 @@ pub const Encoder = struct {
52 // 5 0b00000111 2 0b11100 68 // 5 0b00000111 2 0b11100
53 // 6 0b00000011 3 0b11000 69 // 6 0b00000011 3 0b11000
54 // 7 0b00000001 4 0b10000 70 // 7 0b00000001 4 0b10000
71 const index = self.index orelse return null;
55 const bitmask = @as(u8, 0b11111000) >> self.bit_off; 72 const bitmask = @as(u8, 0b11111000) >> self.bit_off;
56 const bits = self.buffer[index] & bitmask; 73 const bits = self.buffer[index] & bitmask;
57 if (self.bit_off >= 4) return @truncate(u5, bits << (self.bit_off - 3)); 74 if (self.bit_off >= 4) return @truncate(u5, bits << (self.bit_off - 3));
58 return @truncate(u5, bits >> (3 - self.bit_off)); 75 return @truncate(u5, bits >> (3 - self.bit_off));
59 } 76 }
60 77
61 fn back(self: *const Self, index: usize, bits: u3) u5 { 78 // Returns the `self.buffer[self.index]` with the maximum amount specified by the `bits` parameter,
62 if (bits == 0) return 0; 79 // aligned to the right of the 5-bit unsigned integer.
63 return @truncate(u5, self.buffer[index] >> (7 - bits + 1)); 80 // Because a 5-bit integer is returned, not more than 5 bits can be read. `bits` must not be greater than 5.
81 // An illustration of its behaviour, with `self.buffer[self.index]` being 0b11101001:
82 // | `bits` | `backBits` |
83 // |--------|------------|
84 // | 0 | 0b00000 |
85 // | 1 | 0b10000 |
86 // | 2 | 0b11000 |
87 // | 3 | 0b11100 |
88 // | 4 | 0b11100 |
89 // | 5 | 0b11101 |
90 fn backBits(self: *const Self, bits: u3) u5 {
91 std.debug.assert(bits <= 5);
92 if (bits == 0 or self.index == null) return 0;
93 return @truncate(u5, self.buffer[self.index.?] >> (7 - bits + 1));
64 } 94 }
65 95
96 // Returns the next 5-bit integer, read from `self.buffer`.
66 fn next_u5(self: *Self) ?u5 { 97 fn next_u5(self: *Self) ?u5 {
67 const front_index = self.index orelse return null; 98 // `self.buffer` is read 5 bits at a time by `next_u5`.
68 const num_front_bits = self.n_front_bits(); 99 // Because of the elements of `self.buffer` being 8 bits each, we need to
69 const front_bits = self.front(front_index); 100 // read from 2 bytes from `self.buffer` to return a whole u5.
101 // `front_bits` are the bits that come first, read from `self.buffer[self.index]`.
102 // `back_bits` are the bits that come last, read from `self.buffer[self.index + 1]`.
103 // `back_bits` is only used when we can't read 5 bits from `self.buffer[self.index]`.
104
105 const front_bits = self.frontBits() orelse return null;
106 const n_front_bits = self.frontBitsLen();
70 107
71 var back_bits: u5 = 0; 108 var back_bits: u5 = 0;
72 if (self.bit_off >= 3) { 109 if (self.bit_off >= 3) {
73 self.bit_off -= 3; 110 // Next time we'll need to read from the next byte in `self.buffer`.
74 const new_index = front_index + 1; 111 // We may need to grab the back bits from that next byte for this call too (if it exist).
112 self.bit_off -= 3; // same as self.bit_off + 5 - 8
113 const new_index = self.index.? + 1;
75 if (self.buffer.len > new_index) { 114 if (self.buffer.len > new_index) {
76 self.index = new_index; 115 self.index = new_index;
77 back_bits = self.back(new_index, 5 - num_front_bits); 116 back_bits = self.backBits(5 - n_front_bits);
78 } else { 117 } else {
79 self.index = null; 118 self.index = null;
80 } 119 }
81 } else { 120 } else {
121 // We need to read from the current byte in the next call to `next_u5` too.
82 self.bit_off += 5; 122 self.bit_off += 5;
83 } 123 }
84 124