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