write.clj

Branches > client-handling-rewrite > ab39dc4 > files / src / net / bowmap / codecs / write.clj

(ns net.bowmap.codecs.write
  (:require
   [clojure.data.json :as json]
   [dev.grahp.error :refer [raise]])
  (:import
   [io.netty.buffer ByteBuf]
   [java.nio.charset Charset]))

(defn write-varint! [buf n]
  (loop [buf buf
         n n]
    (let [b (bit-and n 0x7F)
          nxt (unsigned-bit-shift-right n 7)]
      (if (zero? nxt)
        (ByteBuf/.writeByte buf b)
        (recur (ByteBuf/.writeByte buf (bit-or b 0x80))
               nxt)))))

(defn write-string! [buf s]
  (doto buf
    (write-varint! (count s))
    (ByteBuf/.writeCharSequence s (Charset/forName "UTF-8"))))

(defn write-json! [buf s]
  (write-string! buf (json/write-str s)))

(declare writer writers)

;; I think this should have :required/:optional/:prefixed-optional,
;; and have it that non-optional fields are implicity :required and thus nil checked
(defn writer
  "Returns a form that will evaluate to a function that takes a buffer and writes the respective type to it."
  ([t]
   (or (writers t) (raise "No such type!" {:type t})))
  ([t & args]
   (apply (writer t) args)))

(def writers
  {:byte   `ByteBuf/.writeByte
   :ubyte  `ByteBuf/.writeByte
   :short  `ByteBuf/.writeShort
   :ushort `ByteBuf/.writeShort
   :int    `ByteBuf/.writeInt
   :long   `ByteBuf/.writeLong
   :varint `write-varint!
   :string `write-string!
   :json   `write-json!})