Quick Tutorial

Install dependencies and then start a REPL either using shadow-cljs or lumo:

cd clj-protocol
npm install
npx shadow-cljs node-repl
  # OR
lumo -c src

Require some clj-protocol namespaces:

cljs.user=> (require '[protocol.fields :as fields])
cljs.user=> (require '[protocol.header :as header])

Define binary data in a Buffer that we will read/parse:

cljs.user=> (def buf (.from js/Buffer #js [0x61 0x62 0x63 0x64]))

Define a data format spec that specifies two 8-bit unsigned integers followed by two 16-bit unsigned integers:

cljs.user=> (def spec1 [[:f1 :uint8] [:f2 :uint8] [:f3 :uint16]])

Use that spec and big-endian field readers to parse the buffer:

cljs.user=> (prn (header/read-header-full
                   buf 0 {:spec spec1 :readers fields/readers-BE}))
{:f1 97, :f2 98, :f3 25444}

Parse using the same spec but using little-endian field readers:

cljs.user=> (prn (header/read-header-full
                   buf 0 {:spec spec1 :readers fields/readers-LE}))
{:f1 97, :f2 98, :f3 25699}

Define an alternate data format spec that specifies a single fixed length (4 byte) UTF-8 encoded string and then use that to parse the buffer:

cljs.user=> (def spec2 [[:s1 :utf8 {:length 4}]])
cljs.user=> (prn (header/read-header-full
                   buf 0 {:spec spec2 :readers fields/readers-BE}))
{:s1 "abcd"}

Define an alternate spec that species a 4-byte bitfield containing three fields: a 7-bit unsigned integer field, a 1-bit boolean field, and a 24-bit unsigned integer field.

cljs.user=> (def spec3 [[:f1 :bitfield {:length 4
                                        :spec [[:b1 :int   7]
                                               [:b2 :bool  1]
                                               [:b3 :int  24]]}]])
cljs.user=> (prn (header/read-header-full
                   buf 0 {:spec spec3 :readers fields/readers-BE}))
{:f1 {:b1 48, :b2 true, :b3 6447972}}

Use the same bitfield spec to encode different values into a buffer starting at offset 2:

cljs.user=> (def msg {:f1 {:b1 5, :b2 false, :b3 16}})
cljs.user=> (def buf2 (header/write-header-full
                        nil msg 2 {:spec spec3 :writers fields/writers-BE}))
cljs.user=> (prn (vec buf2))
[0 0 10 0 0 16]