1//go:build go1.18
2// +build go1.18
3
4// Copyright (c) Microsoft Corporation. All rights reserved.
5// Licensed under the MIT License.
6
7package uuid
8
9import (
10 "crypto/rand"
11 "errors"
12 "fmt"
13 "strconv"
14)
15
16// The UUID reserved variants.
17const (
18 reservedRFC4122 byte = 0x40
19)
20
21// A UUID representation compliant with specification in RFC4122 document.
22type UUID [16]byte
23
24// New returns a new UUID using the RFC4122 algorithm.
25func New() (UUID, error) {
26 u := UUID{}
27 // Set all bits to pseudo-random values.
28 // NOTE: this takes a process-wide lock
29 _, err := rand.Read(u[:])
30 if err != nil {
31 return u, err
32 }
33 u[8] = (u[8] | reservedRFC4122) & 0x7F // u.setVariant(ReservedRFC4122)
34
35 var version byte = 4
36 u[6] = (u[6] & 0xF) | (version << 4) // u.setVersion(4)
37 return u, nil
38}
39
40// String returns the UUID in "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" format.
41func (u UUID) String() string {
42 return fmt.Sprintf("%x-%x-%x-%x-%x", u[0:4], u[4:6], u[6:8], u[8:10], u[10:])
43}
44
45// Parse parses a string formatted as "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
46// or "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" into a UUID.
47func Parse(s string) (UUID, error) {
48 var uuid UUID
49 // ensure format
50 switch len(s) {
51 case 36:
52 // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
53 case 38:
54 // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
55 s = s[1:37]
56 default:
57 return uuid, errors.New("invalid UUID format")
58 }
59 if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
60 return uuid, errors.New("invalid UUID format")
61 }
62 // parse chunks
63 for i, x := range [16]int{
64 0, 2, 4, 6,
65 9, 11,
66 14, 16,
67 19, 21,
68 24, 26, 28, 30, 32, 34} {
69 b, err := strconv.ParseUint(s[x:x+2], 16, 8)
70 if err != nil {
71 return uuid, fmt.Errorf("invalid UUID format: %s", err)
72 }
73 uuid[i] = byte(b)
74 }
75 return uuid, nil
76}