summaryrefslogtreecommitdiffstats
path: root/snowflake.go
diff options
context:
space:
mode:
Diffstat (limited to 'snowflake.go')
-rw-r--r--snowflake.go196
1 files changed, 0 insertions, 196 deletions
diff --git a/snowflake.go b/snowflake.go
deleted file mode 100644
index 92a6124..0000000
--- a/snowflake.go
+++ /dev/null
@@ -1,196 +0,0 @@
-// Package snowflake generates random, URL-safe identifiers.
-//
-// Each ID is 16 bytes of cryptographically secure randomness, encoded as a
-// base62 string. IDs implement encoding.TextMarshaler, json.Marshaler,
-// and database/sql.Scanner/Valuer for convenient serialization.
-package snowflake
-
-import (
- "crypto/rand"
- "database/sql/driver"
- "encoding/hex"
- "errors"
- "fmt"
-)
-
-const (
- // IDByteSize is the size of a Snowflake ID in bytes.
- IDByteSize = 16
- // Alphabet is the base62 character set used for encoding.
- Alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
-)
-
-var (
- ErrInvalidIDLength = errors.New("snowflake: invalid ID byte length")
- ErrInvalidEncoding = errors.New("snowflake: invalid encoding string")
- decodeLUT [256]int8
-)
-
-func init() {
- for i := range decodeLUT {
- decodeLUT[i] = -1
- }
-
- for i := 0; i < len(Alphabet); i++ {
- decodeLUT[Alphabet[i]] = int8(i)
- }
-}
-
-// Snowflake is a 16-byte random identifier.
-type Snowflake struct {
- bytes [IDByteSize]byte
-}
-
-// New returns a new random Snowflake ID.
-func New() Snowflake {
- var s Snowflake
- if _, err := rand.Read(s.bytes[:]); err != nil {
- panic(err)
- }
- return s
-}
-
-// Zero returns the zero value of Snowflake.
-func Zero() Snowflake {
- return Snowflake{}
-}
-
-// IsZero reports whether s is the zero value.
-func (s Snowflake) IsZero() bool {
- return s == Snowflake{}
-}
-
-// String returns the base62 encoding of the ID.
-func (s Snowflake) String() string {
- base := uint64(len(Alphabet))
- var res [64]byte
- i := len(res)
-
- tmp := s.bytes
- for {
- var remainder uint64
- allZero := true
- for j := 0; j < IDByteSize; j++ {
- accumulator := uint64(tmp[j]) + (remainder << 8)
- tmp[j] = byte(accumulator / base)
- remainder = accumulator % base
- if tmp[j] > 0 {
- allZero = false
- }
- }
- i--
- res[i] = Alphabet[remainder]
- if allZero {
- break
- }
- }
- return string(res[i:])
-}
-
-// FromString parses a base62-encoded Snowflake ID.
-func FromString(s string) (Snowflake, error) {
- var res Snowflake
- base := uint64(len(Alphabet))
-
- for i := 0; i < len(s); i++ {
- charVal := decodeLUT[s[i]]
- if charVal < 0 {
- return res, ErrInvalidEncoding
- }
-
- carry := uint64(charVal)
- for j := IDByteSize - 1; j >= 0; j-- {
- accumulator := uint64(res.bytes[j])*base + carry
- res.bytes[j] = byte(accumulator)
- carry = accumulator >> 8
- }
-
- if carry > 0 {
- return Snowflake{}, ErrInvalidEncoding
- }
- }
- return res, nil
-}
-
-// Hex returns the hex-encoded ID.
-func (s Snowflake) Hex() string {
- return hex.EncodeToString(s.bytes[:])
-}
-
-// FromHex parses a hex-encoded Snowflake ID.
-func FromHex(h string) (Snowflake, error) {
- decoded, err := hex.DecodeString(h)
- if err != nil {
- return Snowflake{}, err
- }
- if len(decoded) != IDByteSize {
- return Snowflake{}, ErrInvalidIDLength
- }
- var s Snowflake
- copy(s.bytes[:], decoded)
- return s, nil
-}
-
-// MarshalText implements encoding.TextMarshaler.
-func (s Snowflake) MarshalText() ([]byte, error) {
- return []byte(s.String()), nil
-}
-
-// UnmarshalText implements encoding.TextUnmarshaler.
-func (s *Snowflake) UnmarshalText(text []byte) error {
- id, err := FromString(string(text))
- if err != nil {
- return err
- }
- *s = id
- return nil
-}
-
-// MarshalJSON implements json.Marshaler.
-func (s Snowflake) MarshalJSON() ([]byte, error) {
- str := s.String()
- res := make([]byte, 0, len(str)+2)
- res = append(res, '"')
- res = append(res, str...)
- res = append(res, '"')
- return res, nil
-}
-
-// UnmarshalJSON implements json.Unmarshaler.
-func (s *Snowflake) UnmarshalJSON(data []byte) error {
- if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' {
- return ErrInvalidEncoding
- }
- return s.UnmarshalText(data[1 : len(data)-1])
-}
-
-// Value implements driver.Valuer for database/sql support.
-func (s Snowflake) Value() (driver.Value, error) {
- b := make([]byte, IDByteSize)
- copy(b, s.bytes[:])
- return b, nil
-}
-
-// Scan implements sql.Scanner for database/sql support.
-func (s *Snowflake) Scan(value interface{}) error {
- if value == nil {
- s.bytes = [IDByteSize]byte{}
- return nil
- }
-
- var source []byte
- switch t := value.(type) {
- case []byte:
- source = t
- case string:
- source = []byte(t)
- default:
- return fmt.Errorf("snowflake: cannot scan type %T", value)
- }
-
- if len(source) != IDByteSize {
- return ErrInvalidIDLength
- }
- copy(s.bytes[:], source)
- return nil
-}