uid

package module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 20, 2021 License: MIT Imports: 8 Imported by: 1

README

Unique ID Generator

Сodecov Test golangci-lint

Motivation

I had an experience with UUID, and it's perfect for various use cases. For some number of projects I have few additional requirements which UUID doesn't meet:

  1. Custom size for random hash
  2. Custom string encoder
  3. A unique string should achieve security requirements
  4. Should be readable for business code generation
  5. String representation should be shorter than UUID

How requirements achieved:

  1. By default, used crypto/rand implementation, but it extendable and can be simply changed to any other implementation (math/rand or any custom one)
  2. By default, used base32, which is readable (because of the list of supported symbols), but can be simply replaced to any another implementation
  3. By default, used base32, as a result, 20 random bytes (160 bits) are encoded to 32 symbols (UUID has 122 random bits in 32-36 symbols)
  4. Supported all main base encoders: base16, base32, base36, base62, base64, and all supported by bin int

Quick Architecture Review

The main endpoint which should be used from external applications or libraries is located in the file provider.go. The file can be found functions to create default or custom providers. Provider is a struct that can generate new ID (random number of bytes) or parse from a string, decode from ints, initialize from bytes ID. ID is a struct that can encode or dump the id (random number of bytes) to a string, bytes, ints. Encoder, reader, randomizer are internal entities which use for:

  • Encoder - interface to encode and decode an array of bytes to a string
  • Randomizer - interface to generate a random array of bytes, currently implemented encoder only from crypto/rand which has a secure random implementation
  • Reader - struct implements io.Reader to generate rand from packages crypto/rand and can be implemented from math/rand

Examples

Default Provider

In the file provider.go can be found a list of main exported functions for the project. The default provider has random bytes size 20, randomizer from crypto/rand, the encoder is base32 with disabled paddings.

Generate random base32 string with default provider
package main

import (
	"fmt"
	"github.com/aohorodnyk/uid"
)

func main() {
	p := uid.NewProvider()
	g := p.MustGenerate()

	fmt.Println(g.String()) // WY5WHCHAHISDRI35UOHTQ3ZS4THJRMP3
	fmt.Println(g.Byte()) // [182 59 99 136 224 58 36 56 163 125 163 143 56 111 50 228 206 152 177 251]
	fmt.Println(g.Int16()) // [15286 -30621 15072 14372 32163 -28765 28472 -7118 -26418 -1103]
	fmt.Println(g.Uint16()) // [15286 34915 15072 14372 32163 36771 28472 58418 39118 64433]
	fmt.Println(g.Int32()) // [-2006762570 941898464 -1885110877 -466456776 -72247090]
	fmt.Println(g.Uint32()) // [2288204726 941898464 2409856419 3828510520 4222720206]
	fmt.Println(g.Int64()) // err: size of data must be divisible by 8
	fmt.Println(g.Uint64()) // err: size of data must be divisible by 8
}
Parse ID from previously generated base32 string
package main

import (
	"fmt"
	"github.com/aohorodnyk/uid"
	"log"
)

func main() {
	p := uid.NewProvider()
	g, err := p.Parse("WY5WHCHAHISDRI35UOHTQ3ZS4THJRMP3")
	if err != nil {
		log.Panicln("Cannot parse random string")
	}

	fmt.Println(g.String()) // WY5WHCHAHISDRI35UOHTQ3ZS4THJRMP3
	fmt.Println(g.Byte()) // [182 59 99 136 224 58 36 56 163 125 163 143 56 111 50 228 206 152 177 251]
	fmt.Println(g.Int16()) // [15286 -30621 15072 14372 32163 -28765 28472 -7118 -26418 -1103]
	fmt.Println(g.Uint16()) // [15286 34915 15072 14372 32163 36771 28472 58418 39118 64433]
	fmt.Println(g.Int32()) // [-2006762570 941898464 -1885110877 -466456776 -72247090]
	fmt.Println(g.Uint32()) // [2288204726 941898464 2409856419 3828510520 4222720206]
	fmt.Println(g.Int64()) // err: size of data must be divisible by 8
	fmt.Println(g.Uint64()) // err: size of data must be divisible by 8
}
Generate random base32 string with custom size
package main

import (
	"fmt"
	"github.com/aohorodnyk/uid"
)

func main() {
	p := uid.NewProviderSize(32)
	g := p.MustGenerate()

	fmt.Println(g.String()) // 3C4SZMODOFHXKDFPRZBBEEMBDB22DUL2A6TPOZXAHDAJJO56PGGQ
	fmt.Println(g.Byte()) // [216 185 44 177 195 113 79 117 12 175 142 66 18 17 129 24 117 161 209 122 7 166 247 102 224 56 192 148 187 190 121 141]
	fmt.Println(g.Int16()) // [-17960 -20180 29123 30031 -20724 17038 4370 6273 -24203 31441 -23033 26359 14560 -27456 -16709 -29319]
	fmt.Println(g.Uint16()) // [47576 45356 29123 30031 44812 17038 4370 6273 41333 31441 42503 26359 14560 38080 48827 36217]
	fmt.Println(g.Int32()) // [-1322468904 1968140739 1116647180 411111698 2060558709 1727505927 -1799341856 -1921401157]
	fmt.Println(g.Uint32()) // [2972498392 1968140739 1116647180 411111698 2060558709 1727505927 2495625440 2373566139]
	fmt.Println(g.Int64()) // [8453100110902770136 1765711299029675788 7419581462171722101 -8252355129315936032]
	fmt.Println(g.Uint64()) // [8453100110902770136 1765711299029675788 7419581462171722101 10194388944393615584]
}

To parse the string can be used previous example. Size parameter needed only for random ID generation and ignored in all other methods.

Custom Base62 encoder

All other encoders can be used in the same way.

Generate random base62 string
package main

import (
	"fmt"
	"github.com/aohorodnyk/uid"
)

func main() {
	// Can be used as alternative:
	// * uid.NewProvider62Size(8)
	// * uid.NewProviderCustom(8, uid.NewRand(), uid.NewEncoderBase62())
	// * uid.NewProviderCustom(8, uid.NewRand(), uid.NewEncoderBaseX(62))
	p := uid.NewProviderCustom(8, uid.NewRand(), uid.NewEncoderBase62())
	g := p.MustGenerate()

	fmt.Println(g.String()) // 8twXZ4Nkui7
	fmt.Println(g.Byte()) // [98 186 154 157 247 107 100 139] // 8 bytes
	fmt.Println(g.Int16()) // [-17822 -25190 27639 -29852] // 4 bytes
	fmt.Println(g.Uint16()) // [47714 40346 27639 35684] // 4 bytes
	fmt.Println(g.Int32()) // [-1650804126 -1956353033] // 2 bytes
	fmt.Println(g.Uint32()) // [2644163170 2338614263] // 2 bytes
	fmt.Println(g.Int64()) // [-8402472293521245598] // 1 byte
	fmt.Println(g.Uint64()) // [10044271780188306018] // 1 byte
}
Parse random base62 string
package main

import (
	"fmt"
	"github.com/aohorodnyk/uid"
	"log"
)

func main() {
	// Can be used as alternative:
	// * uid.NewProvider62()
	// * uid.NewProvider62Size(8)
	// * uid.NewProviderCustom(8, uid.NewRand(), uid.NewEncoderBase62())
	// * uid.NewProviderCustom(8, uid.NewRand(), uid.NewEncoderBaseX(62))
	p := uid.NewProviderCustom(8, uid.NewRand(), uid.NewEncoderBase62())
	g, err := p.Parse("8twXZ4Nkui7")
	if err != nil {
		log.Panicln("Cannot parse random string")
	}

	fmt.Println(g.String()) // 8twXZ4Nkui7
	fmt.Println(g.Byte()) // [98 186 154 157 247 107 100 139] // 8 bytes
	fmt.Println(g.Int16()) // [-17822 -25190 27639 -29852] // 4 bytes
	fmt.Println(g.Uint16()) // [47714 40346 27639 35684] // 4 bytes
	fmt.Println(g.Int32()) // [-1650804126 -1956353033] // 2 bytes
	fmt.Println(g.Uint32()) // [2644163170 2338614263] // 2 bytes
	fmt.Println(g.Int64()) // [-8402472293521245598] // 1 byte
	fmt.Println(g.Uint64()) // [10044271780188306018] // 1 byte
}

Contributing

All contributions have to follow the CONTRIBUTING.md document If you have any questions/issues/feature requests do not hesitate to create a ticket.

Documentation

Index

Constants

View Source
const ErrorMsgSizeDivisible2 = "size of data must be divisible by 2"
View Source
const ErrorMsgSizeDivisible4 = "size of data must be divisible by 4"
View Source
const ErrorMsgSizeDivisible8 = "size of data must be divisible by 8"
View Source
const ErrorMsgWrongSizeZero = "size cannot be zero"
View Source
const SizeDefault uint32 = 20
View Source
const SizeInt16 = 2
View Source
const SizeInt32 = 4
View Source
const SizeInt64 = 8
View Source
const SizeUint16 = SizeInt16
View Source
const SizeUint32 = SizeInt32
View Source
const SizeUint64 = SizeInt64

Variables

This section is empty.

Functions

This section is empty.

Types

type Base16Encoding

type Base16Encoding struct{}

func (Base16Encoding) DecodeString

func (b Base16Encoding) DecodeString(s string) ([]byte, error)

func (Base16Encoding) EncodeToString

func (b Base16Encoding) EncodeToString(src []byte) string

type BaseXEncoding

type BaseXEncoding struct {
	// contains filtered or unexported fields
}

func (BaseXEncoding) DecodeString

func (b BaseXEncoding) DecodeString(s string) ([]byte, error)

func (BaseXEncoding) EncodeToString

func (b BaseXEncoding) EncodeToString(src []byte) string

type CryptRandReader

type CryptRandReader struct{}

func (CryptRandReader) Read

func (r CryptRandReader) Read(b []byte) (n int, err error)

type EncError

type EncError struct {
	// contains filtered or unexported fields
}

type Encoder

type Encoder interface {
	EncodeToString(src []byte) string
	DecodeString(s string) ([]byte, error)
}

func NewEncoder

func NewEncoder() Encoder

func NewEncoderBase16Std

func NewEncoderBase16Std() Encoder

func NewEncoderBase32Hex

func NewEncoderBase32Hex() Encoder

func NewEncoderBase32Std

func NewEncoderBase32Std() Encoder

func NewEncoderBase36

func NewEncoderBase36() Encoder

func NewEncoderBase62

func NewEncoderBase62() Encoder

func NewEncoderBase64Std

func NewEncoderBase64Std() Encoder

func NewEncoderBase64Url

func NewEncoderBase64Url() Encoder

func NewEncoderBaseX

func NewEncoderBaseX(base int) Encoder

func NewEncoderCustom

func NewEncoderCustom(encoder Encoder) Encoder

type Encoding

type Encoding struct {
	Encoder
}

type ID

type ID struct {
	// contains filtered or unexported fields
}

func (ID) Byte

func (id ID) Byte() []byte

func (ID) Int16

func (id ID) Int16() ([]int16, error)

func (ID) Int32

func (id ID) Int32() ([]int32, error)

func (ID) Int64

func (id ID) Int64() ([]int64, error)

func (ID) String

func (id ID) String() string

func (ID) Uint16

func (id ID) Uint16() ([]uint16, error)

func (ID) Uint32

func (id ID) Uint32() ([]uint32, error)

func (ID) Uint64

func (id ID) Uint64() ([]uint64, error)

type Identifier

type Identifier interface {
	String() string
	Byte() []byte
	Int16() ([]int16, error)
	Uint16() ([]uint16, error)
	Int32() ([]int32, error)
	Uint32() ([]uint32, error)
	Int64() ([]int64, error)
	Uint64() ([]uint64, error)
}

func NewID

func NewID(data []byte, enc Encoder) Identifier

func NewIDStdBase32

func NewIDStdBase32(data []byte) Identifier

type InternalError

type InternalError struct {
	// contains filtered or unexported fields
}

type MockEncoding

type MockEncoding struct {
	EncodedString string
	DecodedBytes  []byte
	DecodedErr    error
}

func (MockEncoding) DecodeString

func (e MockEncoding) DecodeString(s string) ([]byte, error)

func (MockEncoding) EncodeToString

func (e MockEncoding) EncodeToString(src []byte) string

type MockRandReader

type MockRandReader struct {
	Actual    []byte
	ActualErr error
}

func (MockRandReader) Read

func (r MockRandReader) Read(b []byte) (n int, err error)

type Provider

type Provider interface {
	Generate() (Identifier, error)
	MustGenerate() Identifier
	Parse(id string) (Identifier, error)
	Byte(id []byte) Identifier
	Int16(id []int16) Identifier
	Uint16(id []uint16) Identifier
	Int32(id []int32) Identifier
	Uint32(id []uint32) Identifier
	Int64(id []int64) Identifier
	Uint64(id []uint64) Identifier
}

func NewProvider

func NewProvider() Provider

func NewProvider36

func NewProvider36() Provider

func NewProvider36Size

func NewProvider36Size(size uint32) Provider

func NewProvider62

func NewProvider62() Provider

func NewProvider62Size

func NewProvider62Size(size uint32) Provider

func NewProviderCustom

func NewProviderCustom(size uint32, rand Randomizer, enc Encoder) Provider

func NewProviderSize

func NewProviderSize(size uint32) Provider

func NewProviderUrl64

func NewProviderUrl64() Provider

func NewProviderUrl64Size

func NewProviderUrl64Size(size uint32) Provider

type Providing

type Providing struct {
	// contains filtered or unexported fields
}

func (Providing) Byte

func (p Providing) Byte(id []byte) Identifier

func (Providing) Generate

func (p Providing) Generate() (Identifier, error)

func (Providing) Int16

func (p Providing) Int16(id []int16) Identifier

func (Providing) Int32

func (p Providing) Int32(id []int32) Identifier

func (Providing) Int64

func (p Providing) Int64(id []int64) Identifier

func (Providing) MustGenerate added in v1.1.0

func (p Providing) MustGenerate() Identifier

Generate random identifier or panic error

func (Providing) Parse

func (p Providing) Parse(id string) (Identifier, error)

func (Providing) Uint16

func (p Providing) Uint16(id []uint16) Identifier

func (Providing) Uint32

func (p Providing) Uint32(id []uint32) Identifier

func (Providing) Uint64

func (p Providing) Uint64(id []uint64) Identifier

type Rand

type Rand struct {
	// contains filtered or unexported fields
}

func (Rand) Generate

func (r Rand) Generate(size uint32) ([]byte, error)

type RandError

type RandError struct {
	// contains filtered or unexported fields
}

type Randomizer

type Randomizer interface {
	Generate(size uint32) ([]byte, error)
}

func NewRand

func NewRand() Randomizer

func NewRandCustom

func NewRandCustom(r io.Reader) Randomizer

type WrongSizeError

type WrongSizeError struct {
	// contains filtered or unexported fields
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL