Skip to content

Commit

Permalink
refactor to a single source file
Browse files Browse the repository at this point in the history
  • Loading branch information
jackspirou committed Sep 18, 2024
1 parent 7244e58 commit a9621fa
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 152 deletions.
24 changes: 9 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,21 +120,15 @@ const (
// KeyPartsCount is the number of parts in a valid UUID Key.
KeyPartsCount = KeyHyphenCount + 1
)
```
<a name="UUIDLength"></a>
```go
const (
// UUIDLength is the standard length of a UUID string, including hyphens.
// Reference: RFC 4122 (https://tools.ietf.org/html/rfc4122)
UUIDLength = 36
)
```
<a name="Key"></a>
## type [Key](<https://github.com/agentstation/uuidkey/blob/master/uuidkey.go#L25>)
## type [Key](<https://github.com/agentstation/uuidkey/blob/master/uuidkey.go#L34>)
Key is a UUID Key string.
Expand All @@ -143,7 +137,7 @@ type Key string
```
<a name="Encode"></a>
### func [Encode](<https://github.com/agentstation/uuidkey/blob/master/codec.go#L33>)
### func [Encode](<https://github.com/agentstation/uuidkey/blob/master/uuidkey.go#L118>)
```go
func Encode(uuid string) (Key, error)
Expand All @@ -152,7 +146,7 @@ func Encode(uuid string) (Key, error)
Encode will encode a given UUID string into a Key with basic length validation.
<a name="EncodeBytes"></a>
### func [EncodeBytes](<https://github.com/agentstation/uuidkey/blob/master/codec.go#L62>)
### func [EncodeBytes](<https://github.com/agentstation/uuidkey/blob/master/uuidkey.go#L147>)
```go
func EncodeBytes(uuid [16]byte) (Key, error)
Expand All @@ -161,7 +155,7 @@ func EncodeBytes(uuid [16]byte) (Key, error)
EncodeBytes encodes a \[16\]byte UUID into a Key.
<a name="Parse"></a>
### func [Parse](<https://github.com/agentstation/uuidkey/blob/master/uuidkey.go#L33>)
### func [Parse](<https://github.com/agentstation/uuidkey/blob/master/uuidkey.go#L42>)
```go
func Parse(key string) (Key, error)
Expand All @@ -170,7 +164,7 @@ func Parse(key string) (Key, error)
Parse converts a Key formatted string into a Key type.
<a name="Key.Bytes"></a>
### func \(Key\) [Bytes](<https://github.com/agentstation/uuidkey/blob/master/codec.go#L111>)
### func \(Key\) [Bytes](<https://github.com/agentstation/uuidkey/blob/master/uuidkey.go#L196>)
```go
func (k Key) Bytes() ([16]byte, error)
Expand All @@ -179,7 +173,7 @@ func (k Key) Bytes() ([16]byte, error)
Bytes converts a Key to a \[16\]byte UUID.
<a name="Key.Decode"></a>
### func \(Key\) [Decode](<https://github.com/agentstation/uuidkey/blob/master/codec.go#L82>)
### func \(Key\) [Decode](<https://github.com/agentstation/uuidkey/blob/master/uuidkey.go#L167>)
```go
func (k Key) Decode() (string, error)
Expand All @@ -188,7 +182,7 @@ func (k Key) Decode() (string, error)
Decode will decode a given Key into a UUID string with basic length validation.
<a name="Key.String"></a>
### func \(Key\) [String](<https://github.com/agentstation/uuidkey/blob/master/uuidkey.go#L28>)
### func \(Key\) [String](<https://github.com/agentstation/uuidkey/blob/master/uuidkey.go#L37>)
```go
func (k Key) String() string
Expand All @@ -197,7 +191,7 @@ func (k Key) String() string
String will convert your Key into a string.
<a name="Key.UUID"></a>
### func \(Key\) [UUID](<https://github.com/agentstation/uuidkey/blob/master/uuidkey.go#L86>)
### func \(Key\) [UUID](<https://github.com/agentstation/uuidkey/blob/master/uuidkey.go#L95>)
```go
func (k Key) UUID() (string, error)
Expand All @@ -206,7 +200,7 @@ func (k Key) UUID() (string, error)
UUID will validate and convert a given Key into a UUID string.
<a name="Key.Valid"></a>
### func \(Key\) [Valid](<https://github.com/agentstation/uuidkey/blob/master/uuidkey.go#L59>)
### func \(Key\) [Valid](<https://github.com/agentstation/uuidkey/blob/master/uuidkey.go#L68>)
```go
func (k Key) Valid() bool
Expand Down
137 changes: 0 additions & 137 deletions codec.go

This file was deleted.

131 changes: 131 additions & 0 deletions uuidkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ package uuidkey

import (
"errors"
"fmt"
"strconv"
"strings"

"github.com/richardlehane/crock32"
)

// Key validation constraint constants
Expand All @@ -19,6 +24,10 @@ const (

// KeyPartsCount is the number of parts in a valid UUID Key.
KeyPartsCount = KeyHyphenCount + 1

// UUIDLength is the standard length of a UUID string, including hyphens.
// Reference: RFC 4122 (https://tools.ietf.org/html/rfc4122)
UUIDLength = 36
)

// Key is a UUID Key string.
Expand Down Expand Up @@ -89,3 +98,125 @@ func (k Key) UUID() (string, error) {
}
return k.Decode()
}

// encode will convert your given int64 into base32 crockford encoding format
func encode(n uint64) string {
encoded := crock32.Encode(n)
padding := 7 - len(encoded)
return strings.ToUpper((strings.Repeat("0", padding) + encoded))
}

// decode will convert your given string into original UUID part string
func decode(s string) string {
i, _ := crock32.Decode(s)
decoded := strconv.FormatUint(i, 16)
padding := 8 - len(decoded)
return (strings.Repeat("0", padding) + decoded)
}

// Encode will encode a given UUID string into a Key with basic length validation.
func Encode(uuid string) (Key, error) {
if len(uuid) != UUIDLength { // basic length validation to ensure we can encode
return "", fmt.Errorf("invalid UUID length: expected %d characters, got %d", UUIDLength, len(uuid))
}

// select the 5 parts of the UUID string
s1 := uuid[0:8] // [d1756360]-5da0-40df-9926-a76abff5601d
s2 := uuid[9:13] // d1756360-[5da0]-40df-9926-a76abff5601d
s3 := uuid[14:18] // d1756360-5da0-[40df]-9926-a76abff5601d
s4 := uuid[19:23] // d1756360-5da0-40df-[9926]-a76abff5601d
s5 := uuid[24:36] // d1756360-5da0-40df-9926-[a76abff5601d]

// decode each string part into uint64
n1, _ := strconv.ParseUint(s1, 16, 32)
n2, _ := strconv.ParseUint(s2+s3, 16, 32) // combine s2 and s3
n3, _ := strconv.ParseUint(s4+s5[:4], 16, 32) // combine s4 and the first 4 chars of s5
n4, _ := strconv.ParseUint(s5[4:], 16, 32) // the last 8 chars of s5

// encode each uint64 into base32 crockford encoding format
e1 := encode(n1)
e2 := encode(n2)
e3 := encode(n3)
e4 := encode(n4)

// build and return key
return Key(e1 + "-" + e2 + "-" + e3 + "-" + e4), nil
}

// EncodeBytes encodes a [16]byte UUID into a Key.
func EncodeBytes(uuid [16]byte) (Key, error) {
// Convert byte groups directly to uint64
// Each group of 4 bytes is combined into a single uint64
n1 := uint64(uuid[0])<<24 | uint64(uuid[1])<<16 | uint64(uuid[2])<<8 | uint64(uuid[3])
n2 := uint64(uuid[4])<<24 | uint64(uuid[5])<<16 | uint64(uuid[6])<<8 | uint64(uuid[7])
n3 := uint64(uuid[8])<<24 | uint64(uuid[9])<<16 | uint64(uuid[10])<<8 | uint64(uuid[11])
n4 := uint64(uuid[12])<<24 | uint64(uuid[13])<<16 | uint64(uuid[14])<<8 | uint64(uuid[15])

// Encode each uint64 into base32 crockford encoding format
e1 := encode(n1) // Encodes bytes 0-3
e2 := encode(n2) // Encodes bytes 4-7
e3 := encode(n3) // Encodes bytes 8-11
e4 := encode(n4) // Encodes bytes 12-15

// Build and return key
// The key is constructed by joining the encoded parts with hyphens
return Key(e1 + "-" + e2 + "-" + e3 + "-" + e4), nil
}

// Decode will decode a given Key into a UUID string with basic length validation.
func (k Key) Decode() (string, error) {
if len(k) != KeyLength { // basic length validation to ensure we can decode
return "", fmt.Errorf("invalid Key length: expected %d characters, got %d", KeyLength, len(k))
}

// select the 4 parts of the key string
key := string(k) // convert the type from a Key to string
s1 := key[0:7] // [38QARV0]-1ET0G6Z-2CJD9VA-2ZZAR0X
s2 := key[8:15] // 38QARV0-[1ET0G6Z]-2CJD9VA-2ZZAR0X
s3 := key[16:23] // 38QARV0-1ET0G6Z-[2CJD9VA]-2ZZAR0X
s4 := key[24:31] // 38QARV0-1ET0G6Z-2CJD9VA-[2ZZAR0X]

// decode each string part into original UUID part string
n1 := decode(s1)
n2 := decode(s2)
n3 := decode(s3)
n4 := decode(s4)

// select the 4 parts of the decoded parts
n2a := n2[0:4]
n2b := n2[4:8]
n3a := n3[0:4]
n3b := n3[4:8]

// build and return UUID string
return (n1 + "-" + n2a + "-" + n2b + "-" + n3a + "-" + n3b + n4), nil
}

// Bytes converts a Key to a [16]byte UUID.
func (k Key) Bytes() ([16]byte, error) {
keyStr := string(k)

// Check the length of the Key
if len(keyStr) != KeyLength {
return [16]byte{}, fmt.Errorf("invalid Key length: expected %d characters, got %d", KeyLength, len(keyStr))
}

var uuid [16]byte
var err error
var n uint64

// Process each part of the key
for i, part := range [4]string{keyStr[:7], keyStr[8:15], keyStr[16:23], keyStr[24:]} {
if n, err = crock32.Decode(strings.ToLower(part)); err != nil {
return [16]byte{}, fmt.Errorf("failed to decode Key part: %v", err)
}

// Write 4 bytes for each part
uuid[i*4] = byte(n >> 24)
uuid[i*4+1] = byte(n >> 16)
uuid[i*4+2] = byte(n >> 8)
uuid[i*4+3] = byte(n)
}

return uuid, nil
}

0 comments on commit a9621fa

Please sign in to comment.