Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Complex Real-World Example: Decoding a TLV Structure

Type-Length-Value (TLV) encoding is ubiquitous in network protocols. Let’s build a proper parser:

(defun parse-tlv (data)
  "Parse TLV records: 1 byte type, 2 bytes length, N bytes value."
  (parse-tlv data '()))

(defun parse-tlv
  ; No more data
  ([('') acc]
   (lists:reverse acc))

  ; Parse one TLV record
  ([(binary ((type (size 8))
             (len (size 16) big)
             (value (size len) binary)
             rest binary))
    acc]
   (let ((record `#m(type ,type value ,value)))
     (parse-tlv rest (cons record acc))))

  ; Invalid data
  ([_ _acc]
   '#(error invalid_tlv)))

Testing with multiple TLV records:

lfe> (set tlv-data
       (binary ((1 (size 8))           ; Type 1
                (5 (size 16) big)      ; Length 5
                (#"HELLO" binary)      ; Value "HELLO"
                (2 (size 8))           ; Type 2
                (5 (size 16) big)      ; Length 5
                (#"WORLD" binary))))   ; Value "WORLD"
#B(1 0 5 72 69 76 76 79 2 0 5 87 79 82 76 68)

lfe> (parse-tlv tlv-data)
(#m(type 1 value #B(72 69 76 76 79))
 #m(type 2 value #B(87 79 82 76 68)))