1// Copyright (c) 2012 The gocql 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// The uuid package can be used to generate and parse universally unique 6// identifiers, a standardized format in the form of a 128 bit number. 7// 8// http://tools.ietf.org/html/rfc4122 9package gocql 10 11import ( 12 "crypto/rand" 13 "errors" 14 "fmt" 15 "io" 16 "net" 17 "strings" 18 "sync/atomic" 19 "time" 20) 21 22type UUID [16]byte 23 24var hardwareAddr []byte 25var clockSeq uint32 26 27const ( 28 VariantNCSCompat = 0 29 VariantIETF = 2 30 VariantMicrosoft = 6 31 VariantFuture = 7 32) 33 34func init() { 35 if interfaces, err := net.Interfaces(); err == nil { 36 for _, i := range interfaces { 37 if i.Flags&net.FlagLoopback == 0 && len(i.HardwareAddr) > 0 { 38 hardwareAddr = i.HardwareAddr 39 break 40 } 41 } 42 } 43 if hardwareAddr == nil { 44 // If we failed to obtain the MAC address of the current computer, 45 // we will use a randomly generated 6 byte sequence instead and set 46 // the multicast bit as recommended in RFC 4122. 47 hardwareAddr = make([]byte, 6) 48 _, err := io.ReadFull(rand.Reader, hardwareAddr) 49 if err != nil { 50 panic(err) 51 } 52 hardwareAddr[0] = hardwareAddr[0] | 0x01 53 } 54 55 // initialize the clock sequence with a random number 56 var clockSeqRand [2]byte 57 io.ReadFull(rand.Reader, clockSeqRand[:]) 58 clockSeq = uint32(clockSeqRand[1])<<8 | uint32(clockSeqRand[0]) 59} 60 61// ParseUUID parses a 32 digit hexadecimal number (that might contain hypens) 62// representing an UUID. 63func ParseUUID(input string) (UUID, error) { 64 var u UUID 65 j := 0 66 for _, r := range input { 67 switch { 68 case r == '-' && j&1 == 0: 69 continue 70 case r >= '0' && r <= '9' && j < 32: 71 u[j/2] |= byte(r-'0') << uint(4-j&1*4) 72 case r >= 'a' && r <= 'f' && j < 32: 73 u[j/2] |= byte(r-'a'+10) << uint(4-j&1*4) 74 case r >= 'A' && r <= 'F' && j < 32: 75 u[j/2] |= byte(r-'A'+10) << uint(4-j&1*4) 76 default: 77 return UUID{}, fmt.Errorf("invalid UUID %q", input) 78 } 79 j += 1 80 } 81 if j != 32 { 82 return UUID{}, fmt.Errorf("invalid UUID %q", input) 83 } 84 return u, nil 85} 86 87// UUIDFromBytes converts a raw byte slice to an UUID. 88func UUIDFromBytes(input []byte) (UUID, error) { 89 var u UUID 90 if len(input) != 16 { 91 return u, errors.New("UUIDs must be exactly 16 bytes long") 92 } 93 94 copy(u[:], input) 95 return u, nil 96} 97 98// RandomUUID generates a totally random UUID (version 4) as described in 99// RFC 4122. 100func RandomUUID() (UUID, error) { 101 var u UUID 102 _, err := io.ReadFull(rand.Reader, u[:]) 103 if err != nil { 104 return u, err 105 } 106 u[6] &= 0x0F // clear version 107 u[6] |= 0x40 // set version to 4 (random uuid) 108 u[8] &= 0x3F // clear variant 109 u[8] |= 0x80 // set to IETF variant 110 return u, nil 111} 112 113var timeBase = time.Date(1582, time.October, 15, 0, 0, 0, 0, time.UTC).Unix() 114 115// TimeUUID generates a new time based UUID (version 1) using the current 116// time as the timestamp. 117func TimeUUID() UUID { 118 return UUIDFromTime(time.Now()) 119} 120 121// UUIDFromTime generates a new time based UUID (version 1) as described in 122// RFC 4122. This UUID contains the MAC address of the node that generated 123// the UUID, the given timestamp and a sequence number. 124func UUIDFromTime(aTime time.Time) UUID { 125 utcTime := aTime.In(time.UTC) 126 t := int64(utcTime.Unix()-timeBase)*10000000 + int64(utcTime.Nanosecond()/100) 127 clock := atomic.AddUint32(&clockSeq, 1) 128 129 return TimeUUIDWith(t, clock, hardwareAddr) 130} 131 132// TimeUUIDWith generates a new time based UUID (version 1) as described in 133// RFC4122 with given parameters. t is the number of 100's of nanoseconds 134// since 15 Oct 1582 (60bits). clock is the number of clock sequence (14bits). 135// node is a slice to gurarantee the uniqueness of the UUID (up to 6bytes). 136// Note: calling this function does not increment the static clock sequence. 137func TimeUUIDWith(t int64, clock uint32, node []byte) UUID { 138 var u UUID 139 140 u[0], u[1], u[2], u[3] = byte(t>>24), byte(t>>16), byte(t>>8), byte(t) 141 u[4], u[5] = byte(t>>40), byte(t>>32) 142 u[6], u[7] = byte(t>>56)&0x0F, byte(t>>48) 143 144 u[8] = byte(clock >> 8) 145 u[9] = byte(clock) 146 147 copy(u[10:], node) 148 149 u[6] |= 0x10 // set version to 1 (time based uuid) 150 u[8] &= 0x3F // clear variant 151 u[8] |= 0x80 // set to IETF variant 152 153 return u 154} 155 156// String returns the UUID in it's canonical form, a 32 digit hexadecimal 157// number in the form of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. 158func (u UUID) String() string { 159 var offsets = [...]int{0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34} 160 const hexString = "0123456789abcdef" 161 r := make([]byte, 36) 162 for i, b := range u { 163 r[offsets[i]] = hexString[b>>4] 164 r[offsets[i]+1] = hexString[b&0xF] 165 } 166 r[8] = '-' 167 r[13] = '-' 168 r[18] = '-' 169 r[23] = '-' 170 return string(r) 171 172} 173 174// Bytes returns the raw byte slice for this UUID. A UUID is always 128 bits 175// (16 bytes) long. 176func (u UUID) Bytes() []byte { 177 return u[:] 178} 179 180// Variant returns the variant of this UUID. This package will only generate 181// UUIDs in the IETF variant. 182func (u UUID) Variant() int { 183 x := u[8] 184 if x&0x80 == 0 { 185 return VariantNCSCompat 186 } 187 if x&0x40 == 0 { 188 return VariantIETF 189 } 190 if x&0x20 == 0 { 191 return VariantMicrosoft 192 } 193 return VariantFuture 194} 195 196// Version extracts the version of this UUID variant. The RFC 4122 describes 197// five kinds of UUIDs. 198func (u UUID) Version() int { 199 return int(u[6] & 0xF0 >> 4) 200} 201 202// Node extracts the MAC address of the node who generated this UUID. It will 203// return nil if the UUID is not a time based UUID (version 1). 204func (u UUID) Node() []byte { 205 if u.Version() != 1 { 206 return nil 207 } 208 return u[10:] 209} 210 211// Clock extracts the clock sequence of this UUID. It will return zero if the 212// UUID is not a time based UUID (version 1). 213func (u UUID) Clock() uint32 { 214 if u.Version() != 1 { 215 return 0 216 } 217 218 // Clock sequence is the lower 14bits of u[8:10] 219 return uint32(u[8]&0x3F)<<8 | uint32(u[9]) 220} 221 222// Timestamp extracts the timestamp information from a time based UUID 223// (version 1). 224func (u UUID) Timestamp() int64 { 225 if u.Version() != 1 { 226 return 0 227 } 228 return int64(uint64(u[0])<<24|uint64(u[1])<<16| 229 uint64(u[2])<<8|uint64(u[3])) + 230 int64(uint64(u[4])<<40|uint64(u[5])<<32) + 231 int64(uint64(u[6]&0x0F)<<56|uint64(u[7])<<48) 232} 233 234// Time is like Timestamp, except that it returns a time.Time. 235func (u UUID) Time() time.Time { 236 if u.Version() != 1 { 237 return time.Time{} 238 } 239 t := u.Timestamp() 240 sec := t / 1e7 241 nsec := (t % 1e7) * 100 242 return time.Unix(sec+timeBase, nsec).UTC() 243} 244 245// Marshaling for JSON 246func (u UUID) MarshalJSON() ([]byte, error) { 247 return []byte(`"` + u.String() + `"`), nil 248} 249 250// Unmarshaling for JSON 251func (u *UUID) UnmarshalJSON(data []byte) error { 252 str := strings.Trim(string(data), `"`) 253 if len(str) > 36 { 254 return fmt.Errorf("invalid JSON UUID %s", str) 255 } 256 257 parsed, err := ParseUUID(str) 258 if err == nil { 259 copy(u[:], parsed[:]) 260 } 261 262 return err 263} 264 265func (u UUID) MarshalText() ([]byte, error) { 266 return []byte(u.String()), nil 267} 268 269func (u *UUID) UnmarshalText(text []byte) (err error) { 270 *u, err = ParseUUID(string(text)) 271 return 272} 273