2025-03-15 15:36:43 -05:00
|
|
|
package nomino
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"crypto/rand"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
"github.com/deatil/go-encoding/base62"
|
|
|
|
|
"github.com/google/uuid"
|
|
|
|
|
)
|
|
|
|
|
|
2025-03-31 15:46:48 -05:00
|
|
|
// UUIDer is an interface for generating UUIDs, by the [UUID] [Generator].
|
2025-03-31 12:10:05 -05:00
|
|
|
// It is recommended that you use either the [UUIDv4] or [UUIDv7] variables.
|
2025-03-16 12:38:36 -05:00
|
|
|
type UUIDer interface {
|
|
|
|
|
UUID() (uuid.UUID, error)
|
2025-03-15 15:36:43 -05:00
|
|
|
}
|
|
|
|
|
|
2025-03-16 12:38:36 -05:00
|
|
|
// UUIDFunc is a function that generates a UUID.
|
|
|
|
|
type UUIDFunc func() (uuid.UUID, error)
|
|
|
|
|
|
2025-03-31 12:10:05 -05:00
|
|
|
// UUID allows [UUIDFunc] to be used as a [UUIDer].
|
2025-03-16 12:38:36 -05:00
|
|
|
func (u UUIDFunc) UUID() (uuid.UUID, error) {
|
|
|
|
|
return u()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
// UUIDv1. You probably don't want to use this. It is included for completeness sake.
|
|
|
|
|
UUIDv1 = UUIDFunc(uuid.NewUUID)
|
|
|
|
|
// UUIDv4 is the default.
|
|
|
|
|
UUIDv4 = UUIDFunc(uuid.NewRandom)
|
|
|
|
|
// UUIDv6 is primarily a replacement for UUIDv1. You probably should use 4 or 7.
|
|
|
|
|
UUIDv6 = UUIDFunc(uuid.NewV6)
|
|
|
|
|
// UUIDv7 should be used if you want it sortable by time.
|
|
|
|
|
UUIDv7 = UUIDFunc(uuid.NewV7)
|
|
|
|
|
)
|
|
|
|
|
|
2025-03-31 12:10:05 -05:00
|
|
|
// UUID generates a UUID. If nil is passed as an argument,
|
2025-03-16 12:38:36 -05:00
|
|
|
// a UUIDv4 is generated.
|
|
|
|
|
func UUID(u UUIDer) Generator {
|
|
|
|
|
if u == nil {
|
|
|
|
|
u = UUIDv4
|
|
|
|
|
}
|
|
|
|
|
return func(*Config) (string, error) {
|
|
|
|
|
uu, err := u.UUID()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
return uu.String(), nil
|
|
|
|
|
}
|
2025-03-15 15:36:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type randConf struct {
|
|
|
|
|
length int
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-31 12:10:05 -05:00
|
|
|
// RandomOption is an option for the [Random] [Generator].
|
2025-03-15 15:36:43 -05:00
|
|
|
type RandomOption func(*randConf)
|
|
|
|
|
|
2025-03-31 12:10:05 -05:00
|
|
|
// RandomLength controls the length of the string generated by [Random].
|
2025-03-15 15:36:43 -05:00
|
|
|
func RandomLength(length int) RandomOption {
|
|
|
|
|
return func(c *randConf) {
|
|
|
|
|
c.length = length
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getRandomBytes(l int) []byte {
|
|
|
|
|
key := make([]byte, l)
|
2025-03-19 18:05:16 -05:00
|
|
|
_, _ = rand.Read(key)
|
2025-03-15 15:36:43 -05:00
|
|
|
e := base62.StdEncoding.Encode(key)
|
|
|
|
|
return e[:l]
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-19 18:05:16 -05:00
|
|
|
func fillBuffer(buff *strings.Builder, length int) {
|
|
|
|
|
for buff.Len() < length {
|
|
|
|
|
buff.Write(getRandomBytes(length - buff.Len()))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-31 12:10:05 -05:00
|
|
|
// Random generates a random string containing the characters A-Za-z0-9.
|
2025-03-15 15:36:43 -05:00
|
|
|
// By default, it will be eight characters long.
|
|
|
|
|
func Random(opts ...RandomOption) Generator {
|
|
|
|
|
c := randConf{8}
|
|
|
|
|
for _, opt := range opts {
|
|
|
|
|
opt(&c)
|
|
|
|
|
}
|
|
|
|
|
return func(*Config) (string, error) {
|
|
|
|
|
var buff strings.Builder
|
|
|
|
|
buff.Grow(c.length)
|
2025-03-19 18:05:16 -05:00
|
|
|
fillBuffer(&buff, c.length)
|
2025-03-15 15:36:43 -05:00
|
|
|
return buff.String(), nil
|
|
|
|
|
}
|
|
|
|
|
}
|