uuid.go

 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}