read.clj
Branches > client-handling-rewrite > cbd1421 > files / src / net / bowmap / codecs / read.clj
(ns net.bowmap.codecs.read
(:require
[dev.grahp.error :refer [ensure-not! raise]])
(:import
[io.netty.buffer ByteBuf]
[java.nio.charset Charset]))
(defn can-read-packet?
"Returns whether a varint length can be read from buf, and whether buf has enough bytes to read a full packet.
Can throw if varint is too long, meaning it is completely invalid."
[buf]
(loop [num-read 0
result 0]
(if (>= num-read 5)
(raise "VarInt too long")
(when (< num-read (ByteBuf/.readableBytes buf))
(let [b (ByteBuf/.getByte buf (+ (ByteBuf/.readerIndex buf)
num-read))
result' (bit-or result (bit-shift-left (bit-and b 0x7F) (* 7 num-read)))]
(if (zero? (bit-and b 0x80))
(>= (ByteBuf/.readableBytes buf) (+ result' num-read 1))
(recur (inc num-read) result')))))))
(defn read-varint! [buf]
(loop [num-read 0
result 0]
(if (>= num-read 5)
(raise "VarInt too long")
(let [b (ByteBuf/.readByte buf)
result' (bit-or result (bit-shift-left (bit-and b 0x7F) (* 7 num-read)))]
(if (zero? (bit-and b 0x80))
result'
(recur (inc num-read) result'))))))
(defn read-string! [buf]
(let [len (read-varint! buf)]
(ensure-not! neg? len)
(ByteBuf/.readCharSequence buf len (Charset/forName "UTF-8"))))
(defn read-enum! [codec m buf]
(m (codec buf)))
(defn read-array [codec len buf])
(declare readers reader)
(defn reader
"Returns a form that will evaluate to a function that takes a buffer and reads the respective type from it."
([t]
(or (readers t) (raise "No such type!" {:type t})))
([t & args]
(apply (reader t) args)))
(def readers
{:byte `ByteBuf/.readByte
:ubyte `(comp unchecked-byte ByteBuf/.readByte)
:short `ByteBuf/.readShort
:ushort `(comp unchecked-short ByteBuf/.readShort)
:int `ByteBuf/.readInt
:long `ByteBuf/.readLong
:varint `read-varint!
:string `read-string!
:enum (fn [t m]
`(fn [buf#] (read-enum! ~(reader t) ~m buf#)))})