github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/util/uuid/uuid.go (about)

     1  // Copyright 2019 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  // Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru>
    12  // Use of this source code is governed by a MIT-style
    13  // license that can be found in licenses/MIT-gofrs.txt.
    14  
    15  // This code originated in github.com/gofrs/uuid.
    16  
    17  package uuid
    18  
    19  import (
    20  	"encoding/binary"
    21  	"encoding/hex"
    22  	"fmt"
    23  	"math"
    24  	"time"
    25  
    26  	"github.com/cockroachdb/cockroachdb-parser/pkg/util/timeutil"
    27  	"github.com/cockroachdb/cockroachdb-parser/pkg/util/uint128"
    28  	"github.com/cockroachdb/errors"
    29  )
    30  
    31  // Size of a UUID in bytes.
    32  const Size = 16
    33  
    34  // RFC4122StrSize of a size of the RFC-4122 string representation of UUID.
    35  const RFC4122StrSize = 36
    36  
    37  // Bytes represents a byte slice which is intended to be interpreted as a binary
    38  // encoding of a UUID.
    39  type Bytes []byte
    40  
    41  // GetUUID constructs a UUID from the bytes. If the data is not valid, a zero
    42  // value will be returned.
    43  func (b Bytes) GetUUID() UUID { return FromBytesOrNil(b) }
    44  
    45  // String returns the string representation of the underlying UUID.
    46  func (b Bytes) String() string {
    47  	return b.GetUUID().String()
    48  }
    49  
    50  // UUID is an array type to represent the value of a UUID, as defined in RFC-4122.
    51  type UUID [Size]byte
    52  
    53  // UUID versions.
    54  const (
    55  	_  byte = iota
    56  	V1      // Version 1 (date-time and MAC address)
    57  	_       // Version 2 (date-time and MAC address, DCE security version)
    58  	V3      // Version 3 (namespace name-based)
    59  	V4      // Version 4 (random)
    60  	V5      // Version 5 (namespace name-based)
    61  )
    62  
    63  // UUID layout variants.
    64  const (
    65  	VariantNCS byte = iota
    66  	VariantRFC4122
    67  	VariantMicrosoft
    68  	VariantFuture
    69  )
    70  
    71  // Timestamp is the count of 100-nanosecond intervals since 00:00:00.00,
    72  // 15 October 1582 within a V1 UUID. This type has no meaning for V2-V5
    73  // UUIDs since they don't have an embedded timestamp.
    74  type Timestamp uint64
    75  
    76  const _100nsPerSecond = 10000000
    77  
    78  // Time returns the UTC time.Time representation of a Timestamp
    79  func (t Timestamp) Time() (time.Time, error) {
    80  	secs := uint64(t) / _100nsPerSecond
    81  	nsecs := 100 * (uint64(t) % _100nsPerSecond)
    82  	return timeutil.Unix(int64(secs)-(epochStart/_100nsPerSecond), int64(nsecs)), nil
    83  }
    84  
    85  // TimestampFromV1 returns the Timestamp embedded within a V1 UUID.
    86  // Returns an error if the UUID is any version other than 1.
    87  func TimestampFromV1(u UUID) (Timestamp, error) {
    88  	if u.Version() != 1 {
    89  		err := fmt.Errorf("uuid: %s is version %d, not version 1", u, u.Version())
    90  		return 0, err
    91  	}
    92  	low := binary.BigEndian.Uint32(u[0:4])
    93  	mid := binary.BigEndian.Uint16(u[4:6])
    94  	hi := binary.BigEndian.Uint16(u[6:8]) & 0xfff
    95  	return Timestamp(uint64(low) + (uint64(mid) << 32) + (uint64(hi) << 48)), nil
    96  }
    97  
    98  // String parse helpers.
    99  var urnPrefix = []byte("urn:uuid:")
   100  
   101  // Nil is the nil UUID, as specified in RFC-4122, which has all 128 bits set to
   102  // zero.
   103  var Nil = UUID{}
   104  
   105  // Max is the maximum possible UUID, which has all 128 bits set to 1.
   106  var Max = FromUint128(uint128.FromInts(math.MaxUint64, math.MaxUint64))
   107  
   108  // Predefined namespace UUIDs.
   109  var (
   110  	NamespaceDNS  = Must(FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
   111  	NamespaceURL  = Must(FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
   112  	NamespaceOID  = Must(FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
   113  	NamespaceX500 = Must(FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
   114  )
   115  
   116  // Version returns the algorithm version used to generate the UUID.
   117  func (u UUID) Version() byte {
   118  	return u[6] >> 4
   119  }
   120  
   121  // Variant returns the UUID layout variant.
   122  func (u UUID) Variant() byte {
   123  	switch {
   124  	case (u[8] >> 7) == 0x00:
   125  		return VariantNCS
   126  	case (u[8] >> 6) == 0x02:
   127  		return VariantRFC4122
   128  	case (u[8] >> 5) == 0x06:
   129  		return VariantMicrosoft
   130  	case (u[8] >> 5) == 0x07:
   131  		fallthrough
   132  	default:
   133  		return VariantFuture
   134  	}
   135  }
   136  
   137  // bytes returns a byte slice representation of the UUID. It incurs an
   138  // allocation if the return value escapes.
   139  func (u UUID) bytes() []byte {
   140  	return u[:]
   141  }
   142  
   143  // bytesMut returns a mutable byte slice representation of the UUID. Unlike
   144  // bytes, it does not necessarily incur an allocation if the return value
   145  // escapes. Instead, the return value escaping will cause the method's receiver
   146  // (and any struct that it is a part of) to escape.
   147  func (u *UUID) bytesMut() []byte {
   148  	return u[:]
   149  }
   150  
   151  // String returns a canonical RFC-4122 string representation of the UUID:
   152  // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
   153  func (u UUID) String() string {
   154  	buf := make([]byte, RFC4122StrSize)
   155  	u.StringBytes(buf)
   156  	return string(buf)
   157  }
   158  
   159  // StringBytes writes the result of String directly into a buffer, which must
   160  // have a length of at least 36.
   161  func (u UUID) StringBytes(buf []byte) {
   162  	_ = buf[:RFC4122StrSize]
   163  	hex.Encode(buf[0:8], u[0:4])
   164  	buf[8] = '-'
   165  	hex.Encode(buf[9:13], u[4:6])
   166  	buf[13] = '-'
   167  	hex.Encode(buf[14:18], u[6:8])
   168  	buf[18] = '-'
   169  	hex.Encode(buf[19:23], u[8:10])
   170  	buf[23] = '-'
   171  	hex.Encode(buf[24:], u[10:])
   172  }
   173  
   174  // SetVersion sets the version bits.
   175  func (u *UUID) SetVersion(v byte) {
   176  	u[6] = (u[6] & 0x0f) | (v << 4)
   177  }
   178  
   179  // SetVariant sets the variant bits.
   180  func (u *UUID) SetVariant(v byte) {
   181  	switch v {
   182  	case VariantNCS:
   183  		u[8] = (u[8]&(0xff>>1) | (0x00 << 7))
   184  	case VariantRFC4122:
   185  		u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
   186  	case VariantMicrosoft:
   187  		u[8] = (u[8]&(0xff>>3) | (0x06 << 5))
   188  	case VariantFuture:
   189  		fallthrough
   190  	default:
   191  		u[8] = (u[8]&(0xff>>3) | (0x07 << 5))
   192  	}
   193  }
   194  
   195  // Must is a helper that wraps a call to a function returning (UUID, error)
   196  // and panics if the error is non-nil. It is intended for use in variable
   197  // initializations such as
   198  //
   199  //	var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000"))
   200  func Must(u UUID, err error) UUID {
   201  	if err != nil {
   202  		panic(err)
   203  	}
   204  	return u
   205  }
   206  
   207  // DeterministicV4 overwrites this UUID with one computed deterministically to
   208  // evenly fill the space of possible V4 UUIDs. `n` represents how many UUIDs
   209  // will fill the space and `i` is an index into these `n` (and thus must be in
   210  // the range `[0,n)`). The resulting UUIDs will be unique, evenly-spaced, and
   211  // sorted.
   212  func (u *UUID) DeterministicV4(i, n uint64) {
   213  	if i >= n {
   214  		panic(errors.Errorf(`i must be in [0,%d) was %d`, n, i))
   215  	}
   216  	// V4 uuids are generated by simply filling 16 bytes with random data (then
   217  	// setting the version and variant), so they're randomly distributed through
   218  	// the space of possible values. This also means they're roughly evenly
   219  	// distributed. We guarantee these values to be similarly distributed.
   220  	//
   221  	// So, space the row indexes out to fill the space of the integers
   222  	// representable with 8 bytes. Then, because this involves some floats (and
   223  	// who knows what kind of crazy rounding things can happen when floats are
   224  	// involved), make sure they're unique by sticking the index
   225  	// in the lower 8 bytes. Note that we need to use BigEndian encodings to keep
   226  	// the uuids sorted in the same order as the ints.
   227  	spacing := uint64(float64(i) * float64(math.MaxUint64) / float64(n))
   228  	binary.BigEndian.PutUint64(u[0:8], spacing)
   229  	binary.BigEndian.PutUint64(u[8:16], i)
   230  	u.SetVersion(V4)
   231  	u.SetVariant(VariantRFC4122)
   232  }