github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/twinj/uuid/uuids.go (about) 1 // This package provides RFC4122 UUIDs. 2 // 3 // NewV1, NewV3, NewV4, NewV5, for generating versions 1, 3, 4 4 // and 5 UUIDs as specified in RFC-4122. 5 // 6 // New([]byte), unsafe; NewHex(string); and Parse(string) for 7 // creating UUIDs from existing data. 8 // 9 // The original version was from Krzysztof Kowalik <chris@nu7hat.ch> 10 // Unfortunately, that version was non compliant with RFC4122. 11 // I forked it but have since heavily redesigned it. 12 // 13 // The example code in the specification was also used as reference 14 // for design. 15 // 16 // Copyright (C) 2014 twinj@github.com 2014 MIT style licence 17 package uuid 18 19 /**************** 20 * Date: 31/01/14 21 * Time: 3:35 PM 22 ***************/ 23 24 import ( 25 "encoding" 26 "encoding/hex" 27 "errors" 28 "fmt" 29 "hash" 30 "regexp" 31 "strings" 32 "bytes" 33 ) 34 35 const ( 36 ReservedNCS byte = 0x00 37 ReservedRFC4122 byte = 0x80 // or and A0 if masked with 1F 38 ReservedMicrosoft byte = 0xC0 39 ReservedFuture byte = 0xE0 40 TakeBack byte = 0xF0 41 ) 42 43 const ( 44 45 // Pattern used to parse string representation of the UUID. 46 // Current one allows to parse string where only one opening 47 // or closing bracket or any of the hyphens are optional. 48 // It is only used to extract the main bytes to create a UUID, 49 // so these imperfections are of no consequence. 50 hexPattern = `^(urn\:uuid\:)?[\{(\[]?([A-Fa-f0-9]{8})-?([A-Fa-f0-9]{4})-?([1-5][A-Fa-f0-9]{3})-?([A-Fa-f0-9]{4})-?([A-Fa-f0-9]{12})[\]\})]?$` 51 ) 52 53 var ( 54 parseUUIDRegex = regexp.MustCompile(hexPattern) 55 format string 56 ) 57 58 func init() { 59 SwitchFormat(CleanHyphen) 60 } 61 62 // ****************************************************** UUID 63 64 // The main interface for UUIDs 65 // Each implementation must also implement the UniqueName interface 66 type UUID interface { 67 encoding.BinaryMarshaler 68 encoding.BinaryUnmarshaler 69 70 // Marshals the UUID bytes or data 71 Bytes() (data []byte) 72 73 // Organises data into a new UUID 74 Unmarshal(pData []byte) 75 76 // Size is used where different implementations require 77 // different sizes. Should return the number of bytes in 78 // the implementation. 79 // Enables unmarshal and Bytes to screen for size 80 Size() int 81 82 // Version returns a version number of the algorithm used 83 // to generate the UUID. 84 // This may may behave independently across non RFC4122 UUIDs 85 Version() int 86 87 // Variant returns the UUID Variant 88 // This will be one of the constants: 89 // ReservedRFC4122, 90 // ReservedMicrosoft, 91 // ReservedFuture, 92 // ReservedNCS. 93 // This may behave differently across non RFC4122 UUIDs 94 Variant() byte 95 96 // UUID can be used as a Name within a namespace 97 // Is simply just a String() string method 98 // Returns a formatted version of the UUID. 99 String() string 100 } 101 102 // New creates a UUID from a slice of bytes. 103 // Truncates any bytes past the default length of 16 104 // Will panic if data slice is too small. 105 func New(pData []byte) UUID { 106 o := new(Array) 107 o.Unmarshal(pData[:length]) 108 return o 109 } 110 111 112 // Creates a UUID from a hex string 113 // Will panic if hex string is invalid - will panic even with hyphens and brackets 114 // Expects a clean string use Parse otherwise. 115 func NewHex(pUuid string) UUID { 116 bytes, err := hex.DecodeString(pUuid) 117 if err != nil { 118 panic(err) 119 } 120 return New(bytes) 121 } 122 123 // Parse creates a UUID from a valid string representation. 124 // Accepts UUID string in following formats: 125 // 6ba7b8149dad11d180b400c04fd430c8 126 // 6ba7b814-9dad-11d1-80b4-00c04fd430c8 127 // {6ba7b814-9dad-11d1-80b4-00c04fd430c8} 128 // urn:uuid:6ba7b814-9dad-11d1-80b4-00c04fd430c8 129 // [6ba7b814-9dad-11d1-80b4-00c04fd430c8] 130 // 131 func Parse(pUUID string) (UUID, error) { 132 md := parseUUIDRegex.FindStringSubmatch(pUUID) 133 if md == nil { 134 return nil, errors.New("uuid.Parse: invalid string") 135 } 136 return NewHex(md[2] + md[3] + md[4] + md[5] + md[6]), nil 137 } 138 139 // Digest a namespace UUID and a UniqueName, which then marshals to 140 // a new UUID 141 func Digest(o, pNs UUID, pName UniqueName, pHash hash.Hash) { 142 // Hash writer never returns an error 143 pHash.Write(pNs.Bytes()) 144 pHash.Write([]byte(pName.String())) 145 o.Unmarshal(pHash.Sum(nil)[:o.Size()]) 146 } 147 148 // Function provides a safe way to unmarshal bytes into an 149 // existing UUID. 150 // Checks for length. 151 func UnmarshalBinary(o UUID, pData []byte) error { 152 if len(pData) != o.Size() { 153 return errors.New("uuid.UnmarshalBinary: invalid length") 154 } 155 o.Unmarshal(pData) 156 return nil 157 } 158 159 // ********************************************** UUID Names 160 161 // A UUID Name is a simple string which implements UniqueName 162 // which satisfies the Stringer interface. 163 type Name string 164 165 // Returns the name as a string. Satisfies the Stringer interface. 166 func (o Name) String() string { 167 return string(o) 168 } 169 170 // NewName will create a unique name from several sources 171 func NewName(salt string, pNames ...UniqueName) UniqueName { 172 var s string 173 for _, s2 := range pNames { 174 s += s2.String() 175 } 176 return Name(s + salt) 177 } 178 179 // UniqueName is a Stinger interface 180 // Made for easy passing of IPs, URLs, the several Address types, 181 // Buffers and any other type which implements Stringer 182 // string, []byte types and Hash sums will need to be cast to 183 // the Name type or some other type which implements 184 // Stringer or UniqueName 185 type UniqueName interface { 186 187 // Many go types implement this method for use with printing 188 // Will convert the current type to its native string format 189 String() string 190 } 191 192 // ********************************************** UUID Printing 193 194 // A Format is a pattern used by the stringer interface with which to print 195 // the UUID. 196 type Format string 197 198 const ( 199 Clean Format = "%x%x%x%x%x%x" 200 Curly Format = "{%x%x%x%x%x%x}" 201 Bracket Format = "(%x%x%x%x%x%x)" 202 203 // This is the default format. 204 CleanHyphen Format = "%x-%x-%x-%x%x-%x" 205 206 CurlyHyphen Format = "{%x-%x-%x-%x%x-%x}" 207 BracketHyphen Format = "(%x-%x-%x-%x%x-%x)" 208 GoIdFormat Format = "[%X-%X-%x-%X%X-%x]" 209 ) 210 211 // Gets the current default format pattern 212 func GetFormat() string { 213 return format 214 } 215 216 // Switches the default printing format for ALL UUID strings 217 // A valid format will have 6 groups if the supplied Format does not 218 func SwitchFormat(pFormat Format) { 219 form := string(pFormat) 220 if strings.Count(form, "%") != 6 { 221 panic(errors.New("uuid.switchFormat: invalid formatting")) 222 } 223 format = form 224 } 225 226 // Same as SwitchFormat but will make it uppercase 227 func SwitchFormatUpperCase(pFormat Format) { 228 form := strings.ToUpper(string(pFormat)) 229 SwitchFormat(Format(form)) 230 } 231 232 // Compares whether each UUID is the same 233 func Equal(p1 UUID, p2 UUID) bool { 234 return bytes.Equal(p1.Bytes(), p2.Bytes()) 235 } 236 237 // Format a UUID into a human readable string which matches the given Format 238 // Use this for one time formatting when setting the default using SwitchFormat 239 // is overkill. 240 func Formatter(pUUID UUID, pFormat Format) string { 241 form := string(pFormat) 242 if strings.Count(form, "%") != 6 { 243 panic(errors.New("uuid.Formatter: invalid formatting")) 244 } 245 return formatter(pUUID, form) 246 } 247 248 // ********************************************** UUID Versions 249 250 type UUIDVersion int 251 252 const ( 253 NONE UUIDVersion = iota 254 RFC4122v1 255 DunnoYetv2 256 RFC4122v3 257 RFC4122v4 258 RFC4122v5 259 ) 260 261 // *************************************************** Helpers 262 263 // Retrieves the variant from the given byte 264 func variant(pVariant byte) byte { 265 switch pVariant & variantGet { 266 case ReservedRFC4122, 0xA0: 267 return ReservedRFC4122 268 case ReservedMicrosoft: 269 return ReservedMicrosoft 270 case ReservedFuture: 271 return ReservedFuture 272 } 273 return ReservedNCS 274 } 275 276 // not strictly required 277 func setVariant(pByte *byte, pVariant byte) { 278 switch pVariant { 279 case ReservedRFC4122: 280 *pByte &= variantSet 281 case ReservedFuture, ReservedMicrosoft: 282 *pByte &= 0x1F 283 case ReservedNCS: 284 *pByte &= 0x7F 285 default: 286 panic(errors.New("uuid.setVariant: invalid variant mask")) 287 } 288 *pByte |= pVariant 289 } 290 291 // format a UUID into a human readable string 292 func formatter(pUUID UUID, pFormat string) string { 293 b := pUUID.Bytes() 294 return fmt.Sprintf(pFormat, b[0:4], b[4:6], b[6:8], b[8:9], b[9:10], b[10:pUUID.Size()]) 295 } 296