uuid.go raw

   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  
   7  package uuid
   8  
   9  import (
  10  	"crypto/rand"
  11  	"errors"
  12  	"fmt"
  13  	"strconv"
  14  )
  15  
  16  // The UUID reserved variants.
  17  const (
  18  	reservedRFC4122 byte = 0x40
  19  )
  20  
  21  // A UUID representation compliant with specification in RFC4122 document.
  22  type UUID [16]byte
  23  
  24  // New returns a new UUID using the RFC4122 algorithm.
  25  func 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.
  41  func (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.
  47  func 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  }
  77