package guuid import ( "crypto/rand" "encoding/hex" "errors" "io" "strings" ) const ( uuidByteCount = 16 uuidDashCount = 4 uuidEncodedLength = (uuidByteCount * 2) + uuidDashCount ) var ( dashIndexes = []int { 8, 13, 18, 23 } emptyUUID = UUID {} ) var ( BadLengthError = errors.New("guuid: str isn't of the correct length") BadDashCountError = errors.New("guuid: Bad count of dashes in string") BadDashPositionError = errors.New("guuid: Bad char in string") ) type UUID [uuidByteCount]byte func NewFrom(r io.Reader) (UUID, error) { var uuid UUID _, err := io.ReadFull(r, uuid[:]) if err != nil { return emptyUUID, err } uuid[6] = (uuid[6] & 0x0f) | 0x40 // v4 uuid[8] = (uuid[8] & 0x3f) | 0x80 // variant 10 return uuid, nil } func New() UUID { uuid, err := NewFrom(rand.Reader) if err != nil { panic(err) } return uuid } func (uuid UUID) String() string { dst := [uuidEncodedLength]byte { 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, 0, 0, '-', 0, 0, 0, 0, '-', 0, 0, 0, 0, '-', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } hex.Encode(dst[ 0:8], uuid[0:4]) hex.Encode(dst[ 9:13], uuid[4:6]) hex.Encode(dst[14:18], uuid[6:8]) hex.Encode(dst[19:23], uuid[8:10]) hex.Encode(dst[24:36], uuid[10:]) return string(dst[:]) } func FromString(str string) (UUID, error) { if len(str) != uuidEncodedLength { return emptyUUID, BadLengthError } if strings.Count(str, "-") != uuidDashCount { return emptyUUID, BadDashCountError } for _, idx := range dashIndexes { if str[idx] != '-' { return emptyUUID, BadDashPositionError } } hexstr := strings.Join(strings.Split(str, "-"), "") data, err := hex.DecodeString(hexstr) if err != nil { return emptyUUID, err } return [uuidByteCount]byte(data), nil }