Source file src/uuid/uuid.go

     1  // Copyright 2026 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package uuid provides support for generating and manipulating UUIDs.
     6  //
     7  // See [RFC 9562] for details.
     8  //
     9  // Random components of new UUIDs are generated with a
    10  // cryptographically secure random number generator.
    11  //
    12  // UUIDs may be generated using various algorithms.
    13  // The [New] function returns a new UUID generated using
    14  // an algorithm suitable for most purposes.
    15  //
    16  // [RFC 9562]: https://www.rfc-editor.org/rfc/rfc9562.html
    17  package uuid
    18  
    19  import (
    20  	"bytes"
    21  	"cmp"
    22  	"crypto/rand"
    23  	"encoding/binary"
    24  	"encoding/hex"
    25  	"errors"
    26  	"sync"
    27  	"time"
    28  )
    29  
    30  // A UUID is a Universally Unique Identifier as specified in RFC 9562.
    31  //
    32  // UUIDs are comparable, such as with the == operator.
    33  type UUID [16]byte
    34  
    35  // Parse returns the UUID represented by s.
    36  //
    37  // It accepts strings in the following forms:
    38  //
    39  //	f81d4fae-7dec-11d0-a765-00a0c91e6bf6
    40  //	{f81d4fae-7dec-11d0-a765-00a0c91e6bf6}
    41  //	urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6
    42  //	f81d4fae7dec11d0a76500a0c91e6bf6
    43  //
    44  // Alphabetic characters in the hexadecimal digits may be any case.
    45  func Parse(s string) (UUID, error) {
    46  	var u UUID
    47  	err := u.UnmarshalText([]byte(s))
    48  	return u, err
    49  }
    50  
    51  // MustParse returns the UUID represented by s.
    52  //
    53  // It panics if s is not a valid string representation of a UUID as defined by [Parse].
    54  func MustParse(s string) UUID {
    55  	u, err := Parse(s)
    56  	if err != nil {
    57  		panic(err)
    58  	}
    59  	return u
    60  }
    61  
    62  // New returns a new UUID.
    63  //
    64  // Programs which do not have a need for a specific UUID generation algorithm should use New.
    65  // At this time, New is equivalent to [NewV4].
    66  func New() UUID {
    67  	return NewV4()
    68  }
    69  
    70  // Nil returns the Nil UUID 00000000-0000-0000-0000-000000000000.
    71  //
    72  // The Nil UUID is defined in [Section 5.9 of RFC 9562].
    73  // Note that this is not the same as the Go value nil.
    74  //
    75  // [Section 5.9 of RFC 9562]: https://www.rfc-editor.org/rfc/rfc9562#section-5.9
    76  func Nil() UUID {
    77  	return UUID{}
    78  }
    79  
    80  // Max returns the Max UUID ffffffff-ffff-ffff-ffff-ffffffffffff.
    81  //
    82  // The Max UUID is defined in [Section 5.10 of RFC 9562].
    83  //
    84  // [Section 5.10 of RFC 9562]: https://www.rfc-editor.org/rfc/rfc9562#section-5.10
    85  func Max() UUID {
    86  	return UUID{
    87  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    88  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    89  	}
    90  }
    91  
    92  // String returns the string representation of u.
    93  //
    94  // It uses the lowercase hex-and-dash representation defined in RFC 9562.
    95  func (u UUID) String() string {
    96  	b, _ := u.MarshalText()
    97  	return string(b)
    98  }
    99  
   100  // MarshalText implements the [encoding.TextMarshaler] interface.
   101  // The encoding is the same as returned by [UUID.String]
   102  func (u UUID) MarshalText() ([]byte, error) {
   103  	return u.AppendText(make([]byte, 0, 36))
   104  }
   105  
   106  // AppendText implements the [encoding.TextAppender] interface.
   107  // The encoding is the same as returned by [UUID.String]
   108  func (u UUID) AppendText(b []byte) ([]byte, error) {
   109  	off := len(b)
   110  	b = append(b, "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"...)
   111  	dst := b[off:]
   112  	hex.Encode(dst[0:8], u[0:4])
   113  	hex.Encode(dst[9:13], u[4:6])
   114  	hex.Encode(dst[14:18], u[6:8])
   115  	hex.Encode(dst[19:23], u[8:10])
   116  	hex.Encode(dst[24:36], u[10:16])
   117  	return b, nil
   118  }
   119  
   120  var errInvalid = errors.New("invalid uuid")
   121  
   122  // UnmarshalText implements the [encoding.TextUnmarshaler] interface.
   123  // The UUID is expected in a form accepted by [Parse].
   124  func (u *UUID) UnmarshalText(b []byte) error {
   125  	var dst UUID
   126  	switch len(b) {
   127  	case len("urn:uuid:") + 36:
   128  		// urn:uuid:00000000-0000-0000-0000-000000000000
   129  		b = bytes.TrimPrefix(b, []byte("urn:uuid:"))
   130  	case 2 + 36:
   131  		// {00000000-0000-0000-0000-000000000000}
   132  		b = bytes.TrimPrefix(b, []byte("{"))
   133  		b = bytes.TrimSuffix(b, []byte("}"))
   134  	case 32:
   135  		// 00000000000000000000000000000000
   136  		if _, err := hex.Decode(dst[:], b); err != nil {
   137  			return errInvalid
   138  		}
   139  		*u = dst
   140  		return nil
   141  	}
   142  	// 00000000-0000-0000-0000-000000000000
   143  	if len(b) != 36 {
   144  		return errInvalid
   145  	}
   146  	if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
   147  		return errInvalid
   148  	}
   149  	if _, err := hex.Decode(dst[0:4], b[0:8]); err != nil {
   150  		return errInvalid
   151  	}
   152  	if _, err := hex.Decode(dst[4:6], b[9:13]); err != nil {
   153  		return errInvalid
   154  	}
   155  	if _, err := hex.Decode(dst[6:8], b[14:18]); err != nil {
   156  		return errInvalid
   157  	}
   158  	if _, err := hex.Decode(dst[8:10], b[19:23]); err != nil {
   159  		return errInvalid
   160  	}
   161  	if _, err := hex.Decode(dst[10:16], b[24:36]); err != nil {
   162  		return errInvalid
   163  	}
   164  	*u = dst
   165  	return nil
   166  }
   167  
   168  // Compare compares the UUID u with v.
   169  // If u is before v, it returns -1.
   170  // If u is after v, it returns +1.
   171  // If they are the same, it returns 0.
   172  //
   173  // Compare uses the big-endian byte order defined in
   174  // [Section 6.11 of RFC 9562] for sorting.
   175  //
   176  // [Section 6.11 of RFC 9562]: https://www.rfc-editor.org/rfc/rfc9562#section-6.11
   177  func (u UUID) Compare(v UUID) int {
   178  	for i := range u {
   179  		if c := cmp.Compare(u[i], v[i]); c != 0 {
   180  			return c
   181  		}
   182  	}
   183  	return 0
   184  }
   185  
   186  // NewV4 returns a new version 4 UUID.
   187  //
   188  // Version 4 UUIDs contain 122 bits of random data.
   189  func NewV4() UUID {
   190  	var u UUID
   191  	rand.Read(u[:])
   192  	u.setVersion(4)
   193  	u.setVariant(0b10)
   194  	return u
   195  }
   196  
   197  var (
   198  	v7mu            sync.Mutex
   199  	v7lastSecs      uint64
   200  	v7lastTimestamp uint64
   201  )
   202  
   203  // NewV7 returns a new version 7 UUID.
   204  //
   205  // Version 7 UUIDs contain a timestamp in the most significant 48 bits,
   206  // and at least 62 bits of random data.
   207  //
   208  // NewV7 always returns UUIDs which sort in increasing order,
   209  // except when the system clock moves backwards.
   210  func NewV7() UUID {
   211  	// UUIDv7 is defined in RFC 9562 section 5.7 as:
   212  	//
   213  	//  0                   1                   2                   3
   214  	//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   215  	// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   216  	// |                           unix_ts_ms                          |
   217  	// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   218  	// |          unix_ts_ms           |  ver  |       rand_a          |
   219  	// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   220  	// |var|                        rand_b                             |
   221  	// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   222  	// |                            rand_b                             |
   223  	// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   224  	//
   225  	// We store a 12 bit sub-millisecond timestamp fraction in the rand_a section,
   226  	// as optionally permitted by the RFC.
   227  	v7mu.Lock()
   228  
   229  	// Generate our 60-bit timestamp: 48 bits of millisecond-resolution,
   230  	// followed by 12 bits of 1/4096-millisecond resolution.
   231  	now := time.Now()
   232  	secs := uint64(now.Unix())
   233  	nanos := uint64(now.Nanosecond())
   234  	msecs := nanos / 1000000
   235  	frac := nanos - (1000000 * msecs)
   236  	timestamp := (1000*secs + msecs) << 12 // ms shifted into position
   237  	timestamp += (frac * 4096) / 1000000   // ns converted to 1/4096-ms units
   238  
   239  	if v7lastSecs > secs {
   240  		// Time has gone backwards.
   241  		// This presumably indicates the system clock has changed.
   242  		// Ignore previously-generated UUIDs.
   243  	} else if timestamp <= v7lastTimestamp {
   244  		// This timestamp is the same as a previously-generated UUID.
   245  		// To preserve the property that we generate UUIDs in order,
   246  		// use a timestamp 1/4096 millisecond later than the most recently
   247  		// generated UUID.
   248  		timestamp = v7lastTimestamp + 1
   249  	}
   250  
   251  	v7lastSecs = secs
   252  	v7lastTimestamp = timestamp
   253  	v7mu.Unlock()
   254  
   255  	// Insert a gap for the 4 bits of the ver field into the timestamp.
   256  	hibits := ((timestamp << 4) & 0xffff_ffff_ffff_0000) | (timestamp & 0x0ffff)
   257  
   258  	var u UUID
   259  	binary.BigEndian.PutUint64(u[0:8], hibits)
   260  	rand.Read(u[8:])
   261  	u.setVersion(7)
   262  	u.setVariant(0b10)
   263  
   264  	return u
   265  }
   266  
   267  func (u *UUID) setVersion(version byte) {
   268  	u[6] = (u[6] & 0b0000_1111) | (version << 4)
   269  }
   270  
   271  func (u *UUID) setVariant(variant byte) {
   272  	u[8] = (u[8] & 0b0011_1111) | (variant << 6)
   273  }
   274  

View as plain text