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))))