honeylisp/lib/util.fnl

119 lines
3.3 KiB
Fennel

(local lume (require :lib.lume))
(local json (require :lib.dkjson))
(local core (require :core))
(fn string.fromhex [str]
(str:gsub ".." (fn [cc] (string.char (tonumber cc 16)))))
(fn string.tohex [str]
(str:gsub "." (fn [c] (string.format "%02X" (string.byte c)))))
(fn lo [v] (bit.band v 0xff))
(fn hi [v] (bit.band (bit.rshift v 8) 0xff))
(fn int8-to-bytes [i]
(string.char (lo i)))
(fn int16-to-bytes [i]
(string.char (lo i) (hi i)))
(fn int24-to-bytes [i]
(string.char (lo i) (hi i) (bit.band (bit.rshift i 16) 0xff)))
(fn bytes-to-uint8 [b ?offset]
(string.byte b (+ 1 (or ?offset 0)) (+ 1 (or ?offset 0))))
(fn bytes-to-uint16 [b ?offset]
(local (lo hi) (string.byte b (+ 1 (or ?offset 0)) (+ 2 (or ?offset 0))))
(bit.bor lo (bit.lshift hi 8)))
(fn bytes-to-uint24 [b ?offset]
(local (lo mid hi) (string.byte b (+ 1 (or ?offset 0)) (+ 3 (or ?offset 0))))
(bit.bor lo (bit.lshift mid 8) (bit.lshift hi 16)))
(fn splice [bytes offset str]
(.. (bytes:sub 1 offset)
str
(bytes:sub (+ (length str) offset 1))))
(fn reload [modname]
(tset package.loaded modname nil)
(require modname))
; lume.hotswap really assumes your module is a table
(fn hotswap [modname]
(if (= (type (. package.loaded modname)) :table)
(lume.hotswap modname)
(reload modname)))
(fn mk-swappable-fn [table k]
(fn [...] ((. table k) ...)))
(fn swappable [table]
(local s {})
(each [k v (pairs table)]
(if (= (type v) :function)
(tset s k (mk-swappable-fn table k))
(tset s k v)))
s)
(fn swappable-require [modname]
(swappable (require modname)))
(fn hot-table [modname]
(local tbl {})
(fn find-table []
(let [loaded-pkg (. package.loaded modname)]
(if (= (type loaded-pkg) :table) loaded-pkg tbl)))
(setmetatable {:hot tbl} {
:__index (fn [_ key] (. (find-table) key))
:__newindex (fn [_ key val] (tset (find-table) key val))
}))
(fn readjson [filename]
(local f (io.open filename :r))
(local text (f:read "*a"))
(f:close)
(json.decode text))
(fn writejson [filename value]
(local f (io.open filename :w))
(f:write (json.encode value))
(f:close))
(fn waitfor [pred]
(local coro (coroutine.running))
(core.add_thread
(fn []
(while (not (pred))
(coroutine.yield))
(coroutine.resume coro))
coro)
(coroutine.yield))
(fn in-coro [f ...] (-> (coroutine.create f) (coroutine.resume ...)))
(fn multival-next [multival i]
(when (< i multival.n)
(values (+ i 1) (. multival (+ i 1)))))
(fn multival-ipairs [multival]
(values multival-next multival 0))
(fn multival [...]
(local multival {:n (select :# ...) :ipairs multival-ipairs})
(for [i 1 multival.n]
(tset multival i (select i ...)))
multival)
(fn nested-tset [t keys value]
(let [next-key (. keys 1)]
(if (= (length keys) 1) (tset t next-key value)
(do (when (= (. t next-key) nil)
(tset t next-key {}))
(nested-tset (. t next-key) (lume.slice keys 2) value)))))
(fn file-exists [name]
(let [f (io.open name :r)]
(when (not= f nil) (io.close f))
(not= f nil)))
{: int8-to-bytes : int16-to-bytes : int24-to-bytes : bytes-to-uint8 : bytes-to-uint16 : bytes-to-uint24
: splice : lo : hi
: reload : hotswap : swappable :require swappable-require : hot-table : nested-tset
: readjson : writejson : file-exists : waitfor : in-coro : multival}