build-a-compression-tool / lesson-18.md
Lesson 18 · Canonical Huffman coding

The self-describing Huffman codec

Now the pieces become one codec. Today you assemble header plus payload into a self-contained Huffman blob and decode it with nothing but the blob itself, proving the round trip end to end.

The goal

Combine the length header, symbol count, and packed payload into one blob that decodes on its own.

Start here - the target
TO DO
Scenario: A Huffman blob decodes itself
Giventhe input ABRACADABRA
WhenhuffmanEncode builds a blob of the length header, the symbol count, and the packed codes, and huffmanDecode reads only that blob
ThenhuffmanDecode returns ABRACADABRA, byte for byte
Andthe round trip holds for any input with at least one symbol, including a single-symbol input like ZZZZZ
Background

This is the chapter’s payoff: a self-describing Huffman codec. huffmanEncode counts frequencies, builds the lengths (single-symbol edge included), assigns canonical codes, then emits a blob that is the length header, the symbol count (the number of symbols in the message, so the decoder knows when to stop) as a 32-bit field, and the packed payload. huffmanDecode needs nothing else - it parses the header, reads the count, rebuilds the very same codes, and decodes the bits back to the original bytes.

Running ABRACADABRA through both returns it unchanged, and so does a single-symbol input like ZZZZZ, which exercises the length-1 edge from lesson 13 through the whole pipeline. On short inputs the two-bytes-per-symbol table can make the blob larger than the input - that is expected and honest; Huffman wins on longer, skewed data where the payload savings dwarf the fixed table cost. You now have a complete entropy coder. The next chapter attacks a different kind of redundancy - repeated substrings - and later you will feed its output through this very codec.

Make it work
// encode: frequencies -> lengths -> canonical codes
// symbolCount = number of symbols in the message (its length), NOT the
// distinct-symbol count already in the length header
// blob = serializeLengths + uint32(symbolCount) + packedPayload
// decode: parse lengths, read count, rebuild codes, decode payload
// no external state: the blob carries everything the decoder needs
CheckpointDONE
The Huffman codec round-trips as a self-contained blob. The chapter is done - commit and stop here.