src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

uuid.go (2494B)


      1 package rand
      2 
      3 import (
      4 	"encoding/hex"
      5 	"io"
      6 )
      7 
      8 const dash byte = '-'
      9 
     10 // UUIDIdempotencyToken provides a utility to get idempotency tokens in the
     11 // UUID format.
     12 type UUIDIdempotencyToken struct {
     13 	uuid *UUID
     14 }
     15 
     16 // NewUUIDIdempotencyToken returns a idempotency token provider returning
     17 // tokens in the UUID random format using the reader provided.
     18 func NewUUIDIdempotencyToken(r io.Reader) *UUIDIdempotencyToken {
     19 	return &UUIDIdempotencyToken{uuid: NewUUID(r)}
     20 }
     21 
     22 // GetIdempotencyToken returns a random UUID value for Idempotency token.
     23 func (u UUIDIdempotencyToken) GetIdempotencyToken() (string, error) {
     24 	return u.uuid.GetUUID()
     25 }
     26 
     27 // UUID provides computing random UUID version 4 values from a random source
     28 // reader.
     29 type UUID struct {
     30 	randSrc io.Reader
     31 }
     32 
     33 // NewUUID returns an initialized UUID value that can be used to retrieve
     34 // random UUID version 4 values.
     35 func NewUUID(r io.Reader) *UUID {
     36 	return &UUID{randSrc: r}
     37 }
     38 
     39 // GetUUID returns a random UUID version 4 string representation sourced from the random reader the
     40 // UUID was created with. Returns an error if unable to compute the UUID.
     41 func (r *UUID) GetUUID() (string, error) {
     42 	var b [16]byte
     43 	if _, err := io.ReadFull(r.randSrc, b[:]); err != nil {
     44 		return "", err
     45 	}
     46 	r.makeUUIDv4(b[:])
     47 	return format(b), nil
     48 }
     49 
     50 // GetBytes returns a byte slice containing a random UUID version 4 sourced from the random reader the
     51 // UUID was created with. Returns an error if unable to compute the UUID.
     52 func (r *UUID) GetBytes() (u []byte, err error) {
     53 	u = make([]byte, 16)
     54 	if _, err = io.ReadFull(r.randSrc, u); err != nil {
     55 		return u, err
     56 	}
     57 	r.makeUUIDv4(u)
     58 	return u, nil
     59 }
     60 
     61 func (r *UUID) makeUUIDv4(u []byte) {
     62 	// 13th character is "4"
     63 	u[6] = (u[6] & 0x0f) | 0x40 // Version 4
     64 	// 17th character is "8", "9", "a", or "b"
     65 	u[8] = (u[8] & 0x3f) | 0x80 // Variant most significant bits are 10x where x can be either 1 or 0
     66 }
     67 
     68 // Format returns the canonical text representation of a UUID.
     69 // This implementation is optimized to not use fmt.
     70 // Example: 82e42f16-b6cc-4d5b-95f5-d403c4befd3d
     71 func format(u [16]byte) string {
     72 	// https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29
     73 
     74 	var scratch [36]byte
     75 
     76 	hex.Encode(scratch[:8], u[0:4])
     77 	scratch[8] = dash
     78 	hex.Encode(scratch[9:13], u[4:6])
     79 	scratch[13] = dash
     80 	hex.Encode(scratch[14:18], u[6:8])
     81 	scratch[18] = dash
     82 	hex.Encode(scratch[19:23], u[8:10])
     83 	scratch[23] = dash
     84 	hex.Encode(scratch[24:], u[10:])
     85 
     86 	return string(scratch[:])
     87 }