diff --git a/LICENSE b/LICENSE index 7bc8ead..27ef29a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 invipal +Copyright (c) 2024 sirsegv, invipal Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 502cb0b..52ec9a8 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This package is V implementation of [NanoID](https://github.com/ai/nanoid) -Generated from [Go Nanoid](https://github.com/matoous/go-nanoid) +It was forked from [invipal's implemenation](https://github.com/invipal/nanoid), which itself was generated from [Go Nanoid](https://github.com/matoous/go-nanoid) **Safe.** It uses cryptographically strong random generator. @@ -23,7 +23,7 @@ and has the same number of unique options in just 22 symbols instead of 36. Via vpm ```bash -$ v install invipal.nanoid +$ v install squidink7.nanoid ``` ## Usage @@ -31,13 +31,13 @@ $ v install invipal.nanoid Generate ID ```v -id := nanoid.new() or { 'error' } +id := nanoid.new() ``` Generate ID with a custom alphabet and length ```v -id := nanoid.generate('erzurum', 25) or { 'error' } +id := nanoid.generate('erzurum', 25) ``` ## Contribution diff --git a/nanoid.v b/nanoid.v index a175c01..57dee84 100644 --- a/nanoid.v +++ b/nanoid.v @@ -3,17 +3,13 @@ module nanoid import math import crypto.rand -const ( - // default_alphabet is the alphabet used for ID characters by default. - default_alphabet = '_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.runes() - // default length for ID - default_size = 21 -) +// default_alphabet is the alphabet used for ID characters by default. +const default_alphabet = '_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.runes() // get_mask generates bit mask used to obtain bits from the random bytes that are used to get index of random character // from the alphabet. Example: if the alphabet has 6 = (110)_2 characters it is sufficient to use mask 7 = (111)_2 fn get_mask(alphabet_size int) int { - for i := 1; i <= 8; i++ { + for i in 1..9 { mask := (2 << u64(i)) - 1 if mask >= alphabet_size - 1 { return mask @@ -22,8 +18,8 @@ fn get_mask(alphabet_size int) int { return 0 } -// generate is a low-level function to change alphabet and ID size. -pub fn generate(alphabet string, size int) ?string { +// generate_opt is a low-level function to change alphabet and ID size. +pub fn generate_opt(alphabet string, size int) !string { chars := alphabet.runes() if alphabet.len == 0 || alphabet.len > 255 { @@ -40,10 +36,12 @@ pub fn generate(alphabet string, size int) ?string { step := int(math.ceil(ceil_arg)) mut id := []rune{len: size} - // bytes := []byte{len: step} + bytes := rand.read(step) or { return error(err.msg()) } - for j := 0; true; { - for i := 0; i < step; i++ { + + mut j := 0 + for true { + for i in 0..step { curr_byte := bytes[i] & u8(mask) if curr_byte < u8(chars.len) { id[j] = chars[curr_byte] @@ -55,42 +53,39 @@ pub fn generate(alphabet string, size int) ?string { } } - return error('could not generated') + return error('could not generate') +} + +// generate is the same as generate_opt but panics on error. +pub fn generate(alphabet string, size int) string { + return generate_opt(alphabet, size) or { panic(err.msg()) } } -// must_generate is the same as generate but panics on error. -pub fn must_generate(alphabet string, size int) string { - id := generate(alphabet, size) or { panic(err.msg()) } - return id +// Allows the id size to be passed as a parameter +@[params] +pub struct NanoIDParams { + size int = 21 } -// new generates secure URL-friendly unique ID. +// new_opt generates secure URL-friendly unique ID. // Accepts optional parameter - length of the ID to be generated (21 by default). -pub fn new(l ...int) ?string { - mut size := int(0) - if l.len == 0 { - size = default_size - } else if l.len == 1 { - size = l[0] - if size <= 0 { - return error('size must be positive integer') - } - } else { - return error('unexpected parameter') +pub fn new_opt(p NanoIDParams) !string { + mut size := p.size + if size <= 0 { + return error('size must be positive integer') } - bytes := rand.read(size) or { return error(err.msg()) } + bytes := rand.read(size)! mut id := []rune{len: size} - for i := 0; i < size; i++ { + for i in 0..size { id[i] = default_alphabet[bytes[i] & 63] } return id[..size].string() } -// must is the same as new but panics on error. -pub fn must(l ...int) string { - id := new(...l) or { panic(err.msg()) } - return id +// new is the same as new_opt but panics on error. +pub fn new(p NanoIDParams) string { + return new_opt(p) or { panic(err.msg()) } }