garm/vendor/github.com/rogpeppe/fastuuid/uuid.go
Gabriel Adrian Samfira bbbe67bf7c Vendor packages and add Makefile
* Vendors packages
  * Adds a Makefile that uses docker to build a static binary against musl
using alpine linux.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2022-06-30 10:20:32 +00:00

146 lines
4.1 KiB
Go

// Package fastuuid provides fast UUID generation of 192 bit
// universally unique identifiers.
//
// It also provides simple support for 128-bit RFC-4122 V4 UUID strings.
//
// Note that the generated UUIDs are not unguessable - each
// UUID generated from a Generator is adjacent to the
// previously generated UUID.
//
// By way of comparison with two other popular UUID-generation packages, github.com/satori/go.uuid
// and github.com/google/uuid, here are some benchmarks:
//
// BenchmarkNext-4 128272185 9.20 ns/op
// BenchmarkHex128-4 14323180 76.4 ns/op
// BenchmarkContended-4 45741997 26.4 ns/op
// BenchmarkSatoriNext-4 1231281 967 ns/op
// BenchmarkSatoriHex128-4 1000000 1041 ns/op
// BenchmarkSatoriContended-4 1765520 666 ns/op
// BenchmarkGoogleNext-4 1256250 958 ns/op
// BenchmarkGoogleHex128-4 1000000 1044 ns/op
// BenchmarkGoogleContended-4 1746570 690 ns/op
package fastuuid
import (
"crypto/rand"
"encoding/binary"
"encoding/hex"
"errors"
"sync/atomic"
)
// Generator represents a UUID generator that
// generates UUIDs in sequence from a random starting
// point.
type Generator struct {
// The constant seed. The first 8 bytes of this are
// copied into counter and then ignored thereafter.
seed [24]byte
counter uint64
}
// NewGenerator returns a new Generator.
// It can fail if the crypto/rand read fails.
func NewGenerator() (*Generator, error) {
var g Generator
_, err := rand.Read(g.seed[:])
if err != nil {
return nil, errors.New("cannot generate random seed: " + err.Error())
}
g.counter = binary.LittleEndian.Uint64(g.seed[:8])
return &g, nil
}
// MustNewGenerator is like NewGenerator
// but panics on failure.
func MustNewGenerator() *Generator {
g, err := NewGenerator()
if err != nil {
panic(err)
}
return g
}
// Next returns the next UUID from the generator.
// Only the first 8 bytes can differ from the previous
// UUID, so taking a slice of the first 16 bytes
// is sufficient to provide a somewhat less secure 128 bit UUID.
//
// It is OK to call this method concurrently.
func (g *Generator) Next() [24]byte {
x := atomic.AddUint64(&g.counter, 1)
uuid := g.seed
binary.LittleEndian.PutUint64(uuid[:8], x)
return uuid
}
// Hex128 is a convenience method that returns Hex128(g.Next()).
func (g *Generator) Hex128() string {
return Hex128(g.Next())
}
// Hex128 returns an RFC4122 V4 representation of the
// first 128 bits of the given UUID. For example:
//
// f81d4fae-7dec-41d0-8765-00a0c91e6bf6.
//
// Note: before encoding, it swaps bytes 6 and 9
// so that all the varying bits of the UUID as
// returned from Generator.Next are reflected
// in the Hex128 representation.
//
// If you want unpredictable UUIDs, you might want to consider
// hashing the uuid (using SHA256, for example) before passing it
// to Hex128.
func Hex128(uuid [24]byte) string {
// As fastuuid only varies the first 8 bytes of the UUID and we
// don't want to lose any of that variance, swap the UUID
// version byte in that range for one outside it.
uuid[6], uuid[9] = uuid[9], uuid[6]
// Version 4.
uuid[6] = (uuid[6] & 0x0f) | 0x40
// RFC4122 variant.
uuid[8] = uuid[8]&0x3f | 0x80
b := make([]byte, 36)
hex.Encode(b[0:8], uuid[0:4])
b[8] = '-'
hex.Encode(b[9:13], uuid[4:6])
b[13] = '-'
hex.Encode(b[14:18], uuid[6:8])
b[18] = '-'
hex.Encode(b[19:23], uuid[8:10])
b[23] = '-'
hex.Encode(b[24:], uuid[10:16])
return string(b)
}
// ValidHex128 reports whether id is a valid UUID as returned by Hex128
// and various other UUID packages, such as github.com/satori/go.uuid's
// NewV4 function.
//
// Note that it does not allow upper case hex.
func ValidHex128(id string) bool {
if len(id) != 36 {
return false
}
if id[8] != '-' || id[13] != '-' || id[18] != '-' || id[23] != '-' {
return false
}
return isValidHex(id[0:8]) &&
isValidHex(id[9:13]) &&
isValidHex(id[14:18]) &&
isValidHex(id[19:23]) &&
isValidHex(id[24:])
}
func isValidHex(s string) bool {
for i := 0; i < len(s); i++ {
c := s[i]
if !('0' <= c && c <= '9' || 'a' <= c && c <= 'f') {
return false
}
}
return true
}