diff options
Diffstat (limited to 'src/guuid.go')
-rw-r--r-- | src/guuid.go | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/src/guuid.go b/src/guuid.go new file mode 100644 index 0000000..9e3e2ba --- /dev/null +++ b/src/guuid.go @@ -0,0 +1,103 @@ +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 +} |