diff options
Diffstat (limited to 'src/uuid.go')
-rw-r--r-- | src/uuid.go | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/src/uuid.go b/src/uuid.go new file mode 100644 index 0000000..8b953f8 --- /dev/null +++ b/src/uuid.go @@ -0,0 +1,102 @@ +package uuid + +import ( + "crypto/rand" + "encoding/hex" + "errors" + "io" + "strings" +) + + + +const ( + ByteCount = 16 + dashCount = 4 + encodedLength = (ByteCount * 2) + dashCount +) + +var ( + dashIndexes = []int{ 8, 13, 18, 23 } + randomReader = rand.Reader + + ErrBadLength = errors.New( + "uuid: str isn't of the correct length", + ) + ErrBadDashCount = errors.New("uuid: Bad count of dashes in string") + ErrBadDashPosition = errors.New("uuid: Bad char in string") +) + + + +type UUID [ByteCount]byte + + + +func NewFrom(r io.Reader) (UUID, error) { + var uuid UUID + _, err := io.ReadFull(r, uuid[:]) + if err != nil { + return UUID{}, 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(randomReader) + if err != nil { + panic(err) + } + return uuid +} + +func (uuid UUID) String() string { + dst := [encodedLength]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) != encodedLength { + return UUID{}, ErrBadLength + } + + if strings.Count(str, "-") != dashCount { + return UUID{}, ErrBadDashCount + } + + for _, idx := range dashIndexes { + if str[idx] != '-' { + return UUID{}, ErrBadDashPosition + } + } + + hexstr := strings.Join(strings.Split(str, "-"), "") + data, err := hex.DecodeString(hexstr) + if err != nil { + return UUID{}, err + } + + return [ByteCount]byte(data), nil +} |