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 }