~statianzo/janet-nanoid

f7baf5ac64c250e36c3f495376d8b2e9554e7d2b — Jason Staten 4 years ago 82c26ee
working implementation
2 files changed, 42 insertions(+), 0 deletions(-)

A nanoid.janet
A test/nanoid.janet
A nanoid.janet => nanoid.janet +24 -0
@@ 0,0 1,24 @@
(def- DEFAULT_ALPHABET "_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

(def- masks [15 31 63 127 255])

(defn gen [&keys {:size size
                  :alphabet alphabet}] 
  (default size 21)
  (default alphabet DEFAULT_ALPHABET)

  (def mask (find |(>= $ (dec (length alphabet))) masks))
  (def step (->> alphabet
                 (length)
                 (/ (* 1.6 mask size))
                 (math/ceil)))
  (def result (array/new size))
  (while (> size (length result))
    (loop [byte :in (os/cryptorand step) 
           :when (> size (length result))]
      (let [mask-byte (band mask byte)
            char (get alphabet mask-byte)]
        (if char
          (array/push result char))
      )))
  (string/from-bytes ;result))

A test/nanoid.janet => test/nanoid.janet +18 -0
@@ 0,0 1,18 @@
(import ../nanoid :as n)

(loop [x :range [0 100]]
  (assert
    (= 21 (length (n/gen)))
    "generates id of length 21"))

(loop [x :range [0 100]]
  (assert
    (= 10 (length (n/gen :size 10)))
    "generates id of length 10"))

(let [results (table)]
  (loop [x :range [0 1000]]
    (let [id (n/gen)]
      (assert (nil? (results id))
              (string/format "%q not unique" id))
      (put results id true))))