mirror of
https://github.com/jimeh/rands.git
synced 2026-02-19 03:16:39 +00:00
feat(strings): add UUID function to generate random RFC 4122 UUID v4 strings
This commit is contained in:
27
strings.go
27
strings.go
@@ -18,6 +18,7 @@ const (
|
||||
alphabeticChars = upperChars + lowerChars
|
||||
alphanumericChars = alphabeticChars + numericChars
|
||||
dnsLabelChars = lowerNumericChars + "-"
|
||||
uuidHyphen = byte('-')
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -233,6 +234,32 @@ func DNSLabel(n int) (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// UUID returns a random UUID v4 in string format as defined by RFC 4122,
|
||||
// section 4.4.
|
||||
func UUID() (string, error) {
|
||||
b, err := Bytes(16)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
b[6] = (b[6] & 0x0f) | 0x40 // Version: 4 (random)
|
||||
b[8] = (b[8] & 0x3f) | 0x80 // Variant: RFC 4122
|
||||
|
||||
// Construct a UUID v4 string according to RFC 4122 specifications.
|
||||
dst := make([]byte, 36)
|
||||
hex.Encode(dst[0:8], b[0:4]) // time-low
|
||||
dst[8] = uuidHyphen
|
||||
hex.Encode(dst[9:13], b[4:6]) // time-mid
|
||||
dst[13] = uuidHyphen
|
||||
hex.Encode(dst[14:18], b[6:8]) // time-high-and-version
|
||||
dst[18] = uuidHyphen
|
||||
hex.Encode(dst[19:23], b[8:10]) // clock-seq-and-reserved, clock-seq-low
|
||||
dst[23] = uuidHyphen
|
||||
hex.Encode(dst[24:], b[10:]) // node
|
||||
|
||||
return string(dst), nil
|
||||
}
|
||||
|
||||
func isASCII(s string) bool {
|
||||
for _, c := range s {
|
||||
if c > unicode.MaxASCII {
|
||||
|
||||
@@ -70,3 +70,8 @@ func ExampleDNSLabel() {
|
||||
s, _ := rands.DNSLabel(16)
|
||||
fmt.Println(s) // => z0ij9o8qkbs0ru-h
|
||||
}
|
||||
|
||||
func ExampleUUID() {
|
||||
s, _ := rands.UUID()
|
||||
fmt.Println(s) // => a62b8712-f238-43ba-a47e-333f5fffe785
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package rands
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -579,6 +580,34 @@ func BenchmarkDNSLabel(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUUID(t *testing.T) {
|
||||
m := regexp.MustCompile(
|
||||
`^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$`,
|
||||
)
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
got, err := UUID()
|
||||
require.NoError(t, err)
|
||||
require.Regexp(t, m, got)
|
||||
|
||||
raw := strings.ReplaceAll(got, "-", "")
|
||||
b := make([]byte, 16)
|
||||
_, err = hex.Decode(b, []byte(raw))
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, 4, int(b[6]>>4), "version is not 4")
|
||||
require.Equal(t, byte(0x80), b[8]&0xc0,
|
||||
"variant is not RFC 4122",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkUUID(b *testing.B) {
|
||||
for n := 0; n < b.N; n++ {
|
||||
_, _ = UUID()
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user