github.com/MontFerret/ferret@v0.18.0/pkg/stdlib/strings/random.go (about) 1 package strings 2 3 import ( 4 "context" 5 "math/rand" 6 "time" 7 8 "github.com/MontFerret/ferret/pkg/runtime/core" 9 "github.com/MontFerret/ferret/pkg/runtime/values" 10 "github.com/MontFerret/ferret/pkg/runtime/values/types" 11 ) 12 13 const ( 14 letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 15 letterIdxBits = 6 // 6 bits to represent a letter index 16 letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits 17 letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits 18 ) 19 20 // randSrc is a global variable because of this issue 21 // https://github.com/golang/go/issues/8926 22 var randSrc = rand.NewSource(time.Now().UnixNano()) 23 24 // RANDOM_TOKEN generates a pseudo-random token string with the specified length. The algorithm for token generation should be treated as opaque. 25 // @param {Int} len - The desired string length for the token. It must be greater than 0 and at most 65536. 26 // @return {String} - A generated token consisting of lowercase letters, uppercase letters and numbers. 27 func RandomToken(_ context.Context, args ...core.Value) (core.Value, error) { 28 err := core.ValidateArgs(args, 1, 1) 29 30 if err != nil { 31 return values.EmptyString, err 32 } 33 34 err = core.ValidateType(args[0], types.Int) 35 36 if err != nil { 37 return values.EmptyString, err 38 } 39 40 size := args[0].(values.Int) 41 b := make([]byte, size) 42 43 for i, cache, remain := size-1, randSrc.Int63(), letterIdxMax; i >= 0; { 44 if remain == 0 { 45 cache, remain = randSrc.Int63(), letterIdxMax 46 } 47 48 if idx := int(cache & letterIdxMask); idx < len(letterBytes) { 49 b[i] = letterBytes[idx] 50 i-- 51 } 52 53 cache >>= letterIdxBits 54 remain-- 55 } 56 57 return values.NewString(string(b)), nil 58 }