Full Code of edwingeng/wuid for AI

master 29d94c466647 cached
39 files
77.2 KB
29.0k tokens
121 symbols
1 requests
Download .txt
Repository: edwingeng/wuid
Branch: master
Commit: 29d94c466647
Files: 39
Total size: 77.2 KB

Directory structure:
gitextract_35st_wr2/

├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── callback/
│   └── wuid/
│       ├── coverage.sh
│       ├── vet.sh
│       ├── wuid.go
│       └── wuid_test.go
├── check.sh
├── go.mod
├── go.sum
├── internal/
│   ├── coverage.sh
│   ├── vet.sh
│   ├── wuid.go
│   └── wuid_test.go
├── mongo/
│   ├── docker-mongo-client.sh
│   ├── docker-mongo-server.sh
│   └── wuid/
│       ├── coverage.sh
│       ├── vet.sh
│       ├── wuid.go
│       └── wuid_test.go
├── mysql/
│   ├── db.sql
│   ├── docker-mysql-client.sh
│   ├── docker-mysql-server.sh
│   └── wuid/
│       ├── coverage.sh
│       ├── vet.sh
│       ├── wuid.go
│       └── wuid_test.go
├── redis/
│   ├── docker-redis-client.sh
│   ├── docker-redis-server.sh
│   ├── v8/
│   │   └── wuid/
│   │       ├── coverage.sh
│   │       ├── vet.sh
│   │       ├── wuid.go
│   │       └── wuid_test.go
│   └── wuid/
│       ├── coverage.sh
│       ├── vet.sh
│       ├── wuid.go
│       └── wuid_test.go
└── wuid.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
* text=auto eol=lf



================================================
FILE: .gitignore
================================================
# Binaries for programs and plugins
*.exe
*.dll
*.so
*.dylib

# Test binary, build with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/

# Misc
/.idea
/vendor


================================================
FILE: LICENSE
================================================
BSD 3-Clause License

Copyright (c) 2018-2022, Edwin Geng
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: README.md
================================================
# Overview
- `WUID` is a universal unique identifier generator.
- `WUID` is much faster than traditional UUID. Each `WUID` instance can even generate 100M unique identifiers in a single second.
- In the nutshell, `WUID` generates 64-bit integers in sequence. The high 28 bits are loaded from a data source. By now, Redis, MySQL, MongoDB and Callback are supported.
- The uniqueness is guaranteed as long as all `WUID` instances share a same data source or each group of them has a different section ID.
- `WUID` automatically renews the high 28 bits when the low 36 bits are about to run out.
- `WUID` is thread-safe, and lock free.
- Obfuscation is supported.

# Benchmarks
```
BenchmarkWUID           159393580          7.661 ns/op        0 B/op       0 allocs/op
BenchmarkRand           100000000         14.95 ns/op         0 B/op       0 allocs/op
BenchmarkTimestamp      164224915          7.359 ns/op        0 B/op       0 allocs/op
BenchmarkUUID_V1        23629536          43.42 ns/op         0 B/op       0 allocs/op
BenchmarkUUID_V2        29351550          43.96 ns/op         0 B/op       0 allocs/op
BenchmarkUUID_V3         4703044         254.2 ns/op        144 B/op       4 allocs/op
BenchmarkUUID_V4         5796310         210.0 ns/op         16 B/op       1 allocs/op
BenchmarkUUID_V5         4051291         310.7 ns/op        168 B/op       4 allocs/op
BenchmarkRedis              2996       38725 ns/op          160 B/op       5 allocs/op
BenchmarkSnowflake       1000000        2092 ns/op            0 B/op       0 allocs/op
BenchmarkULID            5660170         207.7 ns/op         16 B/op       1 allocs/op
BenchmarkXID            49639082          26.21 ns/op         0 B/op       0 allocs/op
BenchmarkShortID         1312386         922.2 ns/op        320 B/op      11 allocs/op
BenchmarkKsuid          19717675          59.79 ns/op         0 B/op       0 allocs/op
```

# Getting Started
``` bash
go get -u github.com/edwingeng/wuid
```

# Usages
### Redis
``` go
import "github.com/edwingeng/wuid/redis/v8/wuid"

newClient := func() (redis.UniversalClient, bool, error) {
    var client redis.UniversalClient
    // ...
    return client, true, nil
}

// Setup
w := NewWUID("alpha", nil)
err := w.LoadH28FromRedis(newClient, "wuid")
if err != nil {
    panic(err)
}

// Generate
for i := 0; i < 10; i++ {
    fmt.Printf("%#016x\n", w.Next())
}
```

### MySQL
``` go
import "github.com/edwingeng/wuid/mysql/wuid"

openDB := func() (*sql.DB, bool, error) {
    var db *sql.DB
    // ...
    return db, true, nil
}

// Setup
w := NewWUID("alpha", nil)
err := w.LoadH28FromMysql(openDB, "wuid")
if err != nil {
    panic(err)
}

// Generate
for i := 0; i < 10; i++ {
    fmt.Printf("%#016x\n", w.Next())
}
```

### MongoDB
``` go
import "github.com/edwingeng/wuid/mongo/wuid"

newClient := func() (*mongo.Client, bool, error) {
    var client *mongo.Client
    // ...
    return client, true, nil
}

// Setup
w := NewWUID("alpha", nil)
err := w.LoadH28FromMongo(newClient, "test", "wuid", "default")
if err != nil {
    panic(err)
}

// Generate
for i := 0; i < 10; i++ {
    fmt.Printf("%#016x\n", w.Next())
}
```

### Callback
``` go
import "github.com/edwingeng/wuid/callback/wuid"

callback := func() (int64, func(), error) {
    var h28 int64
    // ...
    return h28, nil, nil
}

// Setup
w := NewWUID("alpha", nil)
err := w.LoadH28WithCallback(callback)
if err != nil {
    panic(err)
}

// Generate
for i := 0; i < 10; i++ {
    fmt.Printf("%#016x\n", w.Next())
}
```

# Mysql Table Creation
``` sql
CREATE TABLE IF NOT EXISTS `wuid` (
    `h` int(10) NOT NULL AUTO_INCREMENT,
    `x` tinyint(4) NOT NULL DEFAULT '0',
    PRIMARY KEY (`x`),
    UNIQUE KEY `h` (`h`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
```

# Options

- `WithSection` brands a section ID on each generated number. A section ID must be in between [0, 7].
- `WithStep` sets the step and the floor for each generated number.
- `WithObfuscation` enables number obfuscation.

# Attentions
It is highly recommended to pass a logger to `wuid.NewWUID` and keep an eye on the warnings that include "renew failed". It indicates that the low 36 bits are about to run out in hours to hundreds of hours, and the renewal program failed for some reason. `WUID` will make many renewal attempts until succeeded. 

# Special thanks
- [dustinfog](https://github.com/dustinfog)

# Ports
- swift - https://github.com/ekscrypto/SwiftWUID


================================================
FILE: callback/wuid/coverage.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

go test -cover -coverprofile=c.out -v "$@" && go tool cover -html=c.out


================================================
FILE: callback/wuid/vet.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

printImportantMessage "====== gofmt"
gofmt -w .

printImportantMessage "====== go vet"
go vet ./...

printImportantMessage "====== gocyclo"
gocyclo -over 15 .

printImportantMessage "====== ineffassign"
ineffassign ./...

printImportantMessage "====== misspell"
misspell *


================================================
FILE: callback/wuid/wuid.go
================================================
package wuid

import (
	"errors"
	"github.com/edwingeng/slog"
	"github.com/edwingeng/wuid/internal"
)

// WUID is an extremely fast universal unique identifier generator.
type WUID struct {
	w internal.WUID
}

// NewWUID creates a new WUID instance.
func NewWUID(name string, logger slog.Logger, opts ...Option) *WUID {
	return &WUID{w: *internal.NewWUID(name, logger, opts...)}
}

// Next returns a unique identifier.
func (w *WUID) Next() int64 {
	return w.w.Next()
}

type H28Callback func() (h28 int64, cleanUp func(), err error)

// LoadH28WithCallback invokes cb to acquire a number. The number is used as the high 28 bits
// of all generated numbers. In addition, cb is saved for future renewal.
func (w *WUID) LoadH28WithCallback(cb H28Callback) error {
	if cb == nil {
		return errors.New("cb cannot be nil")
	}

	h28, cleanUp, err := cb()
	if err != nil {
		return err
	}
	if cleanUp != nil {
		defer cleanUp()
	}

	if err = w.w.VerifyH28(h28); err != nil {
		return err
	}

	w.w.Reset(h28 << 36)
	w.w.Infof("<wuid> new h28: %d. name: %s", h28, w.w.Name)

	w.w.Lock()
	defer w.w.Unlock()

	if w.w.Renew != nil {
		return nil
	}
	w.w.Renew = func() error {
		return w.LoadH28WithCallback(cb)
	}

	return nil
}

// RenewNow reacquires the high 28 bits immediately.
func (w *WUID) RenewNow() error {
	return w.w.RenewNow()
}

type Option = internal.Option

// WithH28Verifier adds an extra verifier for the high 28 bits.
func WithH28Verifier(cb func(h28 int64) error) Option {
	return internal.WithH28Verifier(cb)
}

// WithSection brands a section ID on each generated number. A section ID must be in between [0, 7].
func WithSection(section int8) Option {
	return internal.WithSection(section)
}

// WithStep sets the step and the floor for each generated number.
func WithStep(step int64, floor int64) Option {
	return internal.WithStep(step, floor)
}

// WithObfuscation enables number obfuscation.
func WithObfuscation(seed int) Option {
	return internal.WithObfuscation(seed)
}


================================================
FILE: callback/wuid/wuid_test.go
================================================
package wuid

import (
	"errors"
	"fmt"
	"github.com/edwingeng/slog"
	"github.com/edwingeng/wuid/internal"
	"math/rand"
	"strings"
	"sync/atomic"
	"testing"
	"time"
)

var (
	dumb = slog.NewDumbLogger()
)

func TestWUID_LoadH28WithCallback_Error(t *testing.T) {
	w := NewWUID("alpha", dumb)
	err1 := w.LoadH28WithCallback(nil)
	if err1 == nil {
		t.Fatal("LoadH28WithCallback should fail when cb is nil")
	}

	err2 := w.LoadH28WithCallback(func() (int64, func(), error) {
		return 0, nil, errors.New("foo")
	})
	if err2 == nil {
		t.Fatal("LoadH28WithCallback should fail when cb returns an error")
	}

	err3 := w.LoadH28WithCallback(func() (int64, func(), error) {
		return 0, nil, nil
	})
	if err3 == nil {
		t.Fatal("LoadH28WithCallback should fail when cb returns an invalid h28")
	}
}

func TestWUID_LoadH28WithCallback(t *testing.T) {
	var h28, counter int64
	done := func() {
		counter++
	}
	cb := func() (int64, func(), error) {
		return atomic.AddInt64(&h28, 1), done, nil
	}

	w := NewWUID("alpha", dumb)
	err := w.LoadH28WithCallback(cb)
	if err != nil {
		t.Fatal(err)
	}
	for i := 1; i < 1000; i++ {
		if err := w.RenewNow(); err != nil {
			t.Fatal(err)
		}
		v := (int64(i) + 1) << 36
		if atomic.LoadInt64(&w.w.N) != v {
			t.Fatalf("w.w.N is %d, while it should be %d. i: %d", atomic.LoadInt64(&w.w.N), v, i)
		}
		n := rand.Intn(10)
		for j := 0; j < n; j++ {
			w.Next()
		}
	}

	if counter != 1000 {
		t.Fatalf("the callback done do not work as expected. counter: %d", counter)
	}
}

func TestWUID_LoadH28WithCallback_Section(t *testing.T) {
	var h28 int64
	cb := func() (int64, func(), error) {
		return atomic.AddInt64(&h28, 1), nil, nil
	}

	w := NewWUID("alpha", dumb, WithSection(1))
	for i := 0; i < 1000; i++ {
		err := w.LoadH28WithCallback(cb)
		if err != nil {
			t.Fatal(err)
		}
		v := (int64(i) + 1 + 0x1000000) << 36
		if atomic.LoadInt64(&w.w.N) != v {
			t.Fatalf("w.w.N is %d, while it should be %d. i: %d", atomic.LoadInt64(&w.w.N), v, i)
		}
		n := rand.Intn(10)
		for j := 0; j < n; j++ {
			w.Next()
		}
	}
}

func TestWUID_LoadH28WithCallback_Same(t *testing.T) {
	cb := func() (int64, func(), error) {
		return 100, nil, nil
	}

	w1 := NewWUID("alpha", dumb)
	_ = w1.LoadH28WithCallback(cb)
	if err := w1.LoadH28WithCallback(cb); err == nil {
		t.Fatal("LoadH28WithCallback should return an error")
	}

	w2 := NewWUID("alpha", dumb, WithSection(1))
	_ = w2.LoadH28WithCallback(cb)
	if err := w2.LoadH28WithCallback(cb); err == nil {
		t.Fatal("LoadH28WithCallback should return an error")
	}
}

func waitUntilNumRenewedReaches(t *testing.T, w *WUID, expected int64) {
	t.Helper()
	startTime := time.Now()
	for time.Since(startTime) < time.Second {
		if atomic.LoadInt64(&w.w.Stats.NumRenewed) == expected {
			return
		}
		time.Sleep(time.Millisecond * 10)
	}
	t.Fatal("timeout")
}

func TestWUID_Renew(t *testing.T) {
	w := NewWUID("alpha", slog.NewScavenger())
	err := w.LoadH28WithCallback(func() (h28 int64, clean func(), err error) {
		return (atomic.LoadInt64(&w.w.N) >> 36) + 1, nil, nil
	})
	if err != nil {
		t.Fatal(err)
	}

	h28 := atomic.LoadInt64(&w.w.N) >> 36
	atomic.StoreInt64(&w.w.N, (h28<<36)|internal.Bye)
	n1a := w.Next()
	if n1a>>36 != h28 {
		t.Fatal(`n1a>>36 != h28`)
	}

	waitUntilNumRenewedReaches(t, w, 1)
	n1b := w.Next()
	if n1b != (h28+1)<<36+1 {
		t.Fatal(`n1b != (h28+1)<<36+1`)
	}

	atomic.StoreInt64(&w.w.N, ((h28+1)<<36)|internal.Bye)
	n2a := w.Next()
	if n2a>>36 != h28+1 {
		t.Fatal(`n2a>>36 != h28+1`)
	}

	waitUntilNumRenewedReaches(t, w, 2)
	n2b := w.Next()
	if n2b != (h28+2)<<36+1 {
		t.Fatal(`n2b != (h28+2)<<36+1`)
	}

	atomic.StoreInt64(&w.w.N, ((h28+2)<<36)|internal.Bye)
	n3a := w.Next()
	if n3a>>36 != h28+2 {
		t.Fatal(`n3a>>36 != h28+2`)
	}

	waitUntilNumRenewedReaches(t, w, 3)
	n3b := w.Next()
	if n3b != (h28+3)<<36+1 {
		t.Fatal(`n3b != (h28+3)<<36+1`)
	}

	atomic.StoreInt64(&w.w.N, ((h28+2)<<36)+internal.Bye+1)
	for i := 0; i < 100; i++ {
		w.Next()
	}
	if atomic.LoadInt64(&w.w.Stats.NumRenewAttempts) != 3 {
		t.Fatal(`atomic.LoadInt64(&w.w.Stats.NumRenewAttempts) != 3`)
	}

	var num int
	sc := w.w.Logger.(*slog.Scavenger)
	sc.Filter(func(level, msg string) bool {
		if level == slog.LevelInfo && strings.Contains(msg, "renew succeeded") {
			num++
		}
		return true
	})
	if num != 3 {
		t.Fatal(`num != 3`)
	}
}

func Example() {
	callback := func() (int64, func(), error) {
		var h28 int64
		// ...
		return h28, nil, nil
	}

	// Setup
	w := NewWUID("alpha", nil)
	err := w.LoadH28WithCallback(callback)
	if err != nil {
		panic(err)
	}

	// Generate
	for i := 0; i < 10; i++ {
		fmt.Printf("%#016x\n", w.Next())
	}
}


================================================
FILE: check.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

find . -name coverage.sh | xargs -n 1 bash -c \
    'cmp --silent internal/coverage.sh "$0" || echo "files are different. file: $0"'
find . -name vet.sh | xargs -n 1 bash -c \
    'cmp --silent internal/vet.sh "$0" || echo "files are different. file: $0"'


================================================
FILE: go.mod
================================================
module github.com/edwingeng/wuid

go 1.18

require (
	github.com/edwingeng/slog v0.0.0-20221027170832-482f0dfb6247
	github.com/go-redis/redis v6.15.9+incompatible
	github.com/go-redis/redis/v8 v8.11.5
	github.com/go-sql-driver/mysql v1.6.0
	go.mongodb.org/mongo-driver v1.10.2
)

require (
	github.com/cespare/xxhash/v2 v2.1.2 // indirect
	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
	github.com/golang/snappy v0.0.1 // indirect
	github.com/klauspost/compress v1.13.6 // indirect
	github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
	github.com/pkg/errors v0.9.1 // indirect
	github.com/xdg-go/pbkdf2 v1.0.0 // indirect
	github.com/xdg-go/scram v1.1.1 // indirect
	github.com/xdg-go/stringprep v1.0.3 // indirect
	github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
	go.uber.org/atomic v1.10.0 // indirect
	go.uber.org/multierr v1.8.0 // indirect
	go.uber.org/zap v1.23.0 // indirect
	golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
	golang.org/x/net v0.7.0 // indirect
	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
	golang.org/x/sys v0.5.0 // indirect
	golang.org/x/text v0.7.0 // indirect
)


================================================
FILE: go.sum
================================================
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/edwingeng/slog v0.0.0-20221027170832-482f0dfb6247 h1:1Vb/cbeFfMh9q+CxEMLSJlHciX9x3JHdaNyHlvhGxhk=
github.com/edwingeng/slog v0.0.0-20221027170832-482f0dfb6247/go.mod h1:mfngKiTrPWlUpIkQjkVzlumITH8chNhxsAiMklqH4Bo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
go.mongodb.org/mongo-driver v1.10.2 h1:4Wk3cnqOrQCn0P92L3/mmurMxzdvWWs5J9jinAVKD+k=
go.mongodb.org/mongo-driver v1.10.2/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=


================================================
FILE: internal/coverage.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

go test -cover -coverprofile=c.out -v "$@" && go tool cover -html=c.out


================================================
FILE: internal/vet.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

printImportantMessage "====== gofmt"
gofmt -w .

printImportantMessage "====== go vet"
go vet ./...

printImportantMessage "====== gocyclo"
gocyclo -over 15 .

printImportantMessage "====== ineffassign"
ineffassign ./...

printImportantMessage "====== misspell"
misspell *


================================================
FILE: internal/wuid.go
================================================
package internal

import (
	"errors"
	"fmt"
	"github.com/edwingeng/slog"
	"sync"
	"sync/atomic"
)

const (
	// PanicValue indicates when Next starts to panic.
	PanicValue int64 = ((1 << 36) * 96 / 100) & ^1023
	// CriticalValue indicates when to renew the high 28 bits.
	CriticalValue int64 = ((1 << 36) * 80 / 100) & ^1023
	// RenewIntervalMask indicates the 'time' between two renewal attempts.
	RenewIntervalMask int64 = 0x20000000 - 1
)

const (
	Bye = ((CriticalValue + RenewIntervalMask) & ^RenewIntervalMask) - 1
)

const (
	H28Mask = 0x07FFFFFF << 36
	L36Mask = 0x0FFFFFFFFF
)

type WUID struct {
	N     int64
	Step  int64
	Floor int64

	Flags           int8
	Obfuscation     bool
	Monolithic      bool
	ObfuscationMask int64
	Section         int64

	slog.Logger
	Name        string
	H28Verifier func(h28 int64) error

	sync.Mutex
	Renew func() error

	Stats struct {
		NumRenewAttempts int64
		NumRenewed       int64
	}
}

func NewWUID(name string, logger slog.Logger, opts ...Option) (w *WUID) {
	w = &WUID{Step: 1, Name: name, Monolithic: true}
	if logger != nil {
		w.Logger = logger
	} else {
		w.Logger = slog.NewDevelopmentConfig().MustBuild()
	}
	for _, opt := range opts {
		opt(w)
	}
	if !w.Obfuscation || w.Floor == 0 {
		return
	}

	ones := w.Step - 1
	w.ObfuscationMask |= ones
	return
}

func (w *WUID) Next() int64 {
	v1 := atomic.AddInt64(&w.N, w.Step)
	v2 := v1 & L36Mask
	if v2 >= PanicValue {
		panicValue := v1&H28Mask | PanicValue
		atomic.CompareAndSwapInt64(&w.N, v1, panicValue)
		panic(fmt.Errorf("the low 36 bits are about to run out"))
	}
	if v2 >= CriticalValue && v2&RenewIntervalMask == 0 {
		go renewImpl(w)
	}

	switch w.Flags {
	case 0:
		return v1
	case 1:
		x := v1 ^ w.ObfuscationMask
		r := v1&H28Mask | x&L36Mask
		return r
	case 2:
		r := v1 / w.Floor * w.Floor
		return r
	case 3:
		x := v1 ^ w.ObfuscationMask
		q := v1&H28Mask | x&L36Mask
		r := q / w.Floor * w.Floor
		return r
	default:
		panic("impossible")
	}
}

func renewImpl(w *WUID) {
	defer func() {
		atomic.AddInt64(&w.Stats.NumRenewAttempts, 1)
	}()
	defer func() {
		if r := recover(); r != nil {
			w.Warnf("<wuid> panic, renew failed. name: %s, reason: %+v", w.Name, r)
		}
	}()

	err := w.RenewNow()
	if err != nil {
		w.Warnf("<wuid> renew failed. name: %s, reason: %+v", w.Name, err)
	} else {
		w.Infof("<wuid> renew succeeded. name: %s", w.Name)
		atomic.AddInt64(&w.Stats.NumRenewed, 1)
	}
}

func (w *WUID) RenewNow() error {
	w.Lock()
	f := w.Renew
	w.Unlock()
	return f()
}

func (w *WUID) Reset(n int64) {
	if n < 0 {
		panic("n cannot be negative")
	}
	if n&L36Mask >= PanicValue {
		panic("n is too old")
	}

	if w.Monolithic {
		// Empty
	} else {
		const L60Mask = 0x0FFFFFFFFFFFFFFF
		n = n&L60Mask | w.Section
	}
	if w.Floor > 1 {
		if n&(w.Step-1) == 0 {
			atomic.StoreInt64(&w.N, n)
		} else {
			atomic.StoreInt64(&w.N, n&^(w.Step-1)+w.Step)
		}
	} else {
		atomic.StoreInt64(&w.N, n)
	}
}

func (w *WUID) VerifyH28(h28 int64) error {
	if h28 <= 0 {
		return errors.New("h28 must be positive")
	}

	if w.Monolithic {
		if h28 > 0x07FFFFFF {
			return errors.New("h28 should not exceed 0x07FFFFFF")
		}
	} else {
		if h28 > 0x00FFFFFF {
			return errors.New("h28 should not exceed 0x00FFFFFF")
		}
	}

	current := atomic.LoadInt64(&w.N) >> 36
	if w.Monolithic {
		if h28 == current {
			return fmt.Errorf("h28 should be a different value other than %d", h28)
		}
	} else {
		if h28 == current&0x00FFFFFF {
			return fmt.Errorf("h28 should be a different value other than %d", h28)
		}
	}

	if w.H28Verifier != nil {
		if err := w.H28Verifier(h28); err != nil {
			return err
		}
	}

	return nil
}

type Option func(w *WUID)

func WithH28Verifier(cb func(h28 int64) error) Option {
	return func(w *WUID) {
		w.H28Verifier = cb
	}
}

func WithSection(section int8) Option {
	if section < 0 || section > 7 {
		panic("section must be in between [0, 7]")
	}
	return func(w *WUID) {
		w.Monolithic = false
		w.Section = int64(section) << 60
	}
}

func WithStep(step int64, floor int64) Option {
	switch step {
	case 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024:
	default:
		panic("the step must be one of these values: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024")
	}
	if floor != 0 && (floor < 0 || floor >= step) {
		panic(fmt.Errorf("floor must be in between [0, %d)", step))
	}
	return func(w *WUID) {
		if w.Step != 1 {
			panic("a second WithStep detected")
		}
		w.Step = step
		if floor >= 2 {
			w.Floor = floor
			w.Flags |= 2
		}
	}
}

func WithObfuscation(seed int) Option {
	if seed == 0 {
		panic("seed cannot be zero")
	}
	return func(w *WUID) {
		w.Obfuscation = true
		x := uint64(seed)
		x = (x ^ (x >> 30)) * uint64(0xbf58476d1ce4e5b9)
		x = (x ^ (x >> 27)) * uint64(0x94d049bb133111eb)
		x = (x ^ (x >> 31)) & 0x7FFFFFFFFFFFFFFF
		w.ObfuscationMask = int64(x)
		w.Flags |= 1
	}
}


================================================
FILE: internal/wuid_test.go
================================================
package internal

import (
	"errors"
	"github.com/edwingeng/slog"
	"math/rand"
	"sort"
	"strings"
	"sync"
	"sync/atomic"
	"testing"
	"time"
)

func (w *WUID) Scavenger() *slog.Scavenger {
	return w.Logger.(*slog.Scavenger)
}

func TestWUID_Next(t *testing.T) {
	for i := 0; i < 100; i++ {
		w := NewWUID("alpha", nil)
		w.Reset(int64(i+1) << 36)
		v := atomic.LoadInt64(&w.N)
		for j := 0; j < 100; j++ {
			v++
			if id := w.Next(); id != v {
				t.Fatalf("the id is %d, while it should be %d", id, v)
			}
		}
	}
}

func TestWUID_Next_Concurrent(t *testing.T) {
	w := NewWUID("alpha", nil)
	var mu sync.Mutex
	const N1 = 100
	const N2 = 100
	a := make([]int64, 0, N1*N2)

	var wg sync.WaitGroup
	for i := 0; i < N1; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for j := 0; j < N2; j++ {
				id := w.Next()
				mu.Lock()
				a = append(a, id)
				mu.Unlock()
			}
		}()
	}

	wg.Wait()
	sort.Slice(a, func(i, j int) bool {
		return a[i] < a[j]
	})

	for i := 0; i < N1*N2-1; i++ {
		if a[i] == a[i+1] {
			t.Fatalf("duplication detected")
		}
	}
}

func TestWUID_Next_Panic(t *testing.T) {
	const total = 100
	w := NewWUID("alpha", nil)
	atomic.StoreInt64(&w.N, PanicValue)

	ch := make(chan int64, total)
	for i := 0; i < total; i++ {
		go func() {
			defer func() {
				if r := recover(); r != nil {
					ch <- 0
				}
			}()

			ch <- w.Next()
		}()
	}

	for i := 0; i < total; i++ {
		v := <-ch
		if v != 0 {
			t.Fatal("something is wrong with Next()")
		}
	}
}

func waitUntilNumRenewAttemptsReaches(t *testing.T, w *WUID, expected int64) {
	t.Helper()
	startTime := time.Now()
	for time.Since(startTime) < time.Second {
		if atomic.LoadInt64(&w.Stats.NumRenewAttempts) == expected {
			return
		}
		time.Sleep(time.Millisecond * 10)
	}
	t.Fatal("timeout")
}

func waitUntilNumRenewedReaches(t *testing.T, w *WUID, expected int64) {
	t.Helper()
	startTime := time.Now()
	for time.Since(startTime) < time.Second {
		if atomic.LoadInt64(&w.Stats.NumRenewed) == expected {
			return
		}
		time.Sleep(time.Millisecond * 10)
	}
	t.Fatal("timeout")
}

func TestWUID_Renew(t *testing.T) {
	w := NewWUID("alpha", slog.NewScavenger())
	w.Renew = func() error {
		w.Reset(((atomic.LoadInt64(&w.N) >> 36) + 1) << 36)
		return nil
	}

	w.Reset(Bye)
	n1a := w.Next()
	if n1a>>36 != 0 {
		t.Fatal(`n1a>>36 != 0`)
	}

	waitUntilNumRenewedReaches(t, w, 1)
	n1b := w.Next()
	if n1b != 1<<36+1 {
		t.Fatal(`n1b != 1<<36+1`)
	}

	w.Reset(1<<36 | Bye)
	n2a := w.Next()
	if n2a>>36 != 1 {
		t.Fatal(`n2a>>36 != 1`)
	}

	waitUntilNumRenewedReaches(t, w, 2)
	n2b := w.Next()
	if n2b != 2<<36+1 {
		t.Fatal(`n2b != 2<<36+1`)
	}

	w.Reset(2<<36 | Bye + RenewIntervalMask + 1)
	n3a := w.Next()
	if n3a>>36 != 2 {
		t.Fatal(`n3a>>36 != 2`)
	}

	waitUntilNumRenewedReaches(t, w, 3)
	n3b := w.Next()
	if n3b != 3<<36+1 {
		t.Fatal(`n3b != 3<<36+1`)
	}

	w.Reset(Bye + 1)
	for i := 0; i < 100; i++ {
		w.Next()
	}
	if atomic.LoadInt64(&w.Stats.NumRenewAttempts) != 3 {
		t.Fatal(`atomic.LoadInt64(&w.Stats.NumRenewAttempts) != 3`)
	}

	var num int
	w.Scavenger().Filter(func(level, msg string) bool {
		if level == slog.LevelInfo && strings.Contains(msg, "renew succeeded") {
			num++
		}
		return true
	})
	if num != 3 {
		t.Fatal(`num != 3`)
	}
}

func TestWUID_Renew_Error(t *testing.T) {
	w := NewWUID("alpha", slog.NewScavenger())
	w.Renew = func() error {
		return errors.New("foo")
	}

	w.Reset((1 >> 36 << 36) | Bye)
	w.Next()
	waitUntilNumRenewAttemptsReaches(t, w, 1)
	w.Next()

	w.Reset((2 >> 36 << 36) | Bye)
	w.Next()
	waitUntilNumRenewAttemptsReaches(t, w, 2)

	for i := 0; i < 100; i++ {
		w.Next()
	}
	if atomic.LoadInt64(&w.Stats.NumRenewAttempts) != 2 {
		t.Fatal(`atomic.LoadInt64(&w.Stats.NumRenewAttempts) != 2`)
	}
	if atomic.LoadInt64(&w.Stats.NumRenewed) != 0 {
		t.Fatal(`atomic.LoadInt64(&w.Stats.NumRenewed) != 0`)
	}

	var num int
	w.Scavenger().Filter(func(level, msg string) bool {
		if level == slog.LevelWarn && strings.Contains(msg, "renew failed") && strings.Contains(msg, "foo") {
			num++
		}
		return true
	})
	if num != 2 {
		t.Fatal(`num != 2`)
	}
}

func TestWUID_Renew_Panic(t *testing.T) {
	w := NewWUID("alpha", slog.NewScavenger())
	w.Renew = func() error {
		panic("foo")
	}

	w.Reset((1 >> 36 << 36) | Bye)
	w.Next()
	waitUntilNumRenewAttemptsReaches(t, w, 1)
	w.Next()

	w.Reset((2 >> 36 << 36) | Bye)
	w.Next()
	waitUntilNumRenewAttemptsReaches(t, w, 2)

	for i := 0; i < 100; i++ {
		w.Next()
	}
	if atomic.LoadInt64(&w.Stats.NumRenewAttempts) != 2 {
		t.Fatal(`atomic.LoadInt64(&w.Stats.NumRenewAttempts) != 2`)
	}
	if atomic.LoadInt64(&w.Stats.NumRenewed) != 0 {
		t.Fatal(`atomic.LoadInt64(&w.Stats.NumRenewed) != 0`)
	}

	var num int
	w.Scavenger().Filter(func(level, msg string) bool {
		if level == slog.LevelWarn && strings.Contains(msg, "renew failed") && strings.Contains(msg, "foo") {
			num++
		}
		return true
	})
	if num != 2 {
		t.Fatal(`num != 2`)
	}
}

func TestWUID_Step(t *testing.T) {
	const step = 16
	w := NewWUID("alpha", slog.NewScavenger(), WithStep(step, 0))
	w.Reset(17 << 36)

	w.Renew = func() error {
		w.Reset(((atomic.LoadInt64(&w.N) >> 36) + 1) << 36)
		return nil
	}

	for i := int64(1); i < 100; i++ {
		if w.Next()&L36Mask != step*i {
			t.Fatal("w.Next()&L36Mask != step*i")
		}
	}

	n1 := w.Next()
	w.Reset(((n1 >> 36 << 36) | Bye) & ^(step - 1))
	w.Next()
	waitUntilNumRenewedReaches(t, w, 1)
	n2 := w.Next()

	w.Reset(((n2 >> 36 << 36) | Bye) & ^(step - 1))
	w.Next()
	waitUntilNumRenewedReaches(t, w, 2)
	n3 := w.Next()

	if n2>>36-n1>>36 != 1 || n3>>36-n2>>36 != 1 {
		t.Fatalf("the renew mechanism does not work as expected: %x, %x, %x", n1>>36, n2>>36, n3>>36)
	}

	var num int
	w.Scavenger().Filter(func(level, msg string) bool {
		if level == slog.LevelInfo && strings.Contains(msg, "renew succeeded") {
			num++
		}
		return true
	})
	if num != 2 {
		t.Fatal(`num != 2`)
	}

	func() {
		defer func() {
			_ = recover()
		}()
		NewWUID("alpha", nil, WithStep(5, 0))
		t.Fatal("WithStep should have panicked")
	}()
}

func TestWUID_Floor(t *testing.T) {
	r := rand.New(rand.NewSource(time.Now().Unix()))
	allSteps := []int64{1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024}
	for loop := 0; loop < 10000; loop++ {
		step := allSteps[r.Intn(len(allSteps))]
		var floor = r.Int63n(step)
		w := NewWUID("alpha", slog.NewScavenger(), WithStep(step, floor))
		if floor < 2 {
			if w.Flags != 0 {
				t.Fatal(`w.Flags != 0`)
			}
		} else {
			if w.Flags != 2 {
				t.Fatal(`w.Flags != 2`)
			}
		}

		w.Reset(r.Int63n(100) << 36)
		baseValue := atomic.LoadInt64(&w.N)

		for i := int64(1); i < 100; i++ {
			x := w.Next()
			if floor != 0 {
				if reminder := x % floor; reminder != 0 {
					t.Fatal("reminder != 0")
				}
			}
			if x <= baseValue+i*step-step || x > baseValue+i*step {
				t.Fatal("x <= baseValue+i*step-step || x > baseValue+i*step")
			}
		}
	}

	func() {
		defer func() {
			_ = recover()
		}()
		NewWUID("alpha", nil, WithStep(1024, 2000))
		t.Fatal("WithStep should have panicked")
	}()

	func() {
		defer func() {
			_ = recover()
		}()
		NewWUID("alpha", nil, WithStep(1024, 0), WithStep(128, 0))
		t.Fatal("WithStep should have panicked")
	}()
}

func TestWUID_VerifyH28(t *testing.T) {
	w1 := NewWUID("alpha", nil)
	w1.Reset(H28Mask)
	if err := w1.VerifyH28(100); err != nil {
		t.Fatalf("VerifyH28 does not work as expected. n: 100, error: %s", err)
	}
	if err := w1.VerifyH28(0); err == nil {
		t.Fatalf("VerifyH28 does not work as expected. n: 0")
	}
	if err := w1.VerifyH28(0x08000000); err == nil {
		t.Fatalf("VerifyH28 does not work as expected. n: 0x08000000")
	}
	if err := w1.VerifyH28(0x07FFFFFF); err == nil {
		t.Fatalf("VerifyH28 does not work as expected. n: 0x07FFFFFF")
	}

	w2 := NewWUID("alpha", nil, WithSection(1))
	w2.Reset(H28Mask)
	if err := w2.VerifyH28(100); err != nil {
		t.Fatalf("VerifyH28 does not work as expected. section: 1, n: 100, error: %s", err)
	}
	if err := w2.VerifyH28(0); err == nil {
		t.Fatalf("VerifyH28 does not work as expected. section: 1, n: 0")
	}
	if err := w2.VerifyH28(0x01000000); err == nil {
		t.Fatalf("VerifyH28 does not work as expected. section: 1, n: 0x01000000")
	}
	if err := w2.VerifyH28(0x00FFFFFF); err == nil {
		t.Fatalf("VerifyH28 does not work as expected. section: 1, n: 0x00FFFFFF")
	}
}

func TestWithSection_Panic(t *testing.T) {
	for i := -100; i <= 100; i++ {
		func(j int8) {
			defer func() {
				_ = recover()
			}()
			WithSection(j)
			if j >= 8 {
				t.Fatalf("WithSection should only accept the values in [0, 7]. j: %d", j)
			}
		}(int8(i))
	}
}

func TestWithSection_Reset(t *testing.T) {
	for i := 0; i < 28; i++ {
		n := int64(1) << (uint(i) + 36)
		func() {
			defer func() {
				if r := recover(); r != nil {
					if i != 27 {
						t.Fatal(r)
					}
				}
			}()
			for j := int8(1); j < 8; j++ {
				w := NewWUID("alpha", nil, WithSection(j))
				w.Reset(n)
				v := atomic.LoadInt64(&w.N)
				if v>>60 != int64(j) {
					t.Fatalf("w.Section does not work as expected. w.N: %x, n: %x, i: %d, j: %d", v, n, i, j)
				}
			}
		}()
	}

	func() {
		defer func() {
			_ = recover()
		}()
		w := NewWUID("alpha", nil)
		w.Reset((1 << 36) | PanicValue)
		t.Fatal("Reset should have panicked")
	}()
}

func TestWithH28Verifier(t *testing.T) {
	w := NewWUID("alpha", nil, WithH28Verifier(func(h28 int64) error {
		if h28 >= 20 {
			return errors.New("bomb")
		}
		return nil
	}))
	if err := w.VerifyH28(10); err != nil {
		t.Fatal("the H28Verifier should not return error")
	}
	if err := w.VerifyH28(20); err == nil || err.Error() != "bomb" {
		t.Fatal("the H28Verifier was not called")
	}
}

//gocyclo:ignore
func TestWithObfuscation(t *testing.T) {
	w1 := NewWUID("alpha", nil, WithObfuscation(1))
	if w1.Flags != 1 {
		t.Fatal(`w1.Flags != 1`)
	}
	if w1.ObfuscationMask == 0 {
		t.Fatal(`w1.ObfuscationMask == 0`)
	}

	w1.Reset(1 << 36)
	for i := 1; i < 100; i++ {
		v := w1.Next()
		if v&H28Mask != 1<<36 {
			t.Fatal(`v&H28Mask != 1<<36`)
		}
		tmp := v ^ w1.ObfuscationMask
		if tmp&L36Mask != int64(i) {
			t.Fatal(`tmp&L36Mask != int64(i)`)
		}
	}

	w2 := NewWUID("alpha", nil, WithObfuscation(1), WithStep(128, 100))
	if w2.Flags != 3 {
		t.Fatal(`w2.Flags != 3`)
	}
	if w2.ObfuscationMask == 0 {
		t.Fatal(`w2.ObfuscationMask == 0`)
	}

	w2.Reset(1 << 36)
	for i := 1; i < 100; i++ {
		v := w2.Next()
		if v%w2.Floor != 0 {
			t.Fatal(`v%w2.Floor != 0`)
		}
		if v&H28Mask != 1<<36 {
			t.Fatal(`v&H28Mask != 1<<36`)
		}
		tmp := v ^ w2.ObfuscationMask
		if tmp&L36Mask&^(w2.Step-1) != w2.Step*int64(i) {
			t.Fatal(`tmp&L36Mask&^(w2.Step-1) != w2.Step*int64(i)`)
		}
	}

	w3 := NewWUID("alpha", nil, WithObfuscation(1), WithStep(1024, 659))
	if w3.Flags != 3 {
		t.Fatal(`w3.Flags != 3`)
	}
	if w3.ObfuscationMask == 0 {
		t.Fatal(`w3.ObfuscationMask == 0`)
	}

	w3.Reset(1<<36 + 1)
	for i := 1; i < 100; i++ {
		v := w3.Next()
		if v%w3.Floor != 0 {
			t.Fatal(`v%w3.Floor != 0`)
		}
		if v&H28Mask != 1<<36 {
			t.Fatal(`v&H28Mask != 1<<36`)
		}
		tmp := v ^ w3.ObfuscationMask
		if tmp&L36Mask&^(w3.Step-1) != w3.Step*int64(i+1) {
			t.Fatal(`tmp&L36Mask&^(w3.Step-1) != w3.Step*int64(i+1)`)
		}
	}

	func() {
		defer func() {
			_ = recover()
		}()
		NewWUID("alpha", nil, WithObfuscation(0))
		t.Fatal("WithObfuscation should have panicked")
	}()
}


================================================
FILE: mongo/docker-mongo-client.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

docker run -it --rm mongo mongosh host.docker.internal


================================================
FILE: mongo/docker-mongo-server.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

docker run --name mongo-server -p 27017:27017 -d mongo


================================================
FILE: mongo/wuid/coverage.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

go test -cover -coverprofile=c.out -v "$@" && go tool cover -html=c.out


================================================
FILE: mongo/wuid/vet.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

printImportantMessage "====== gofmt"
gofmt -w .

printImportantMessage "====== go vet"
go vet ./...

printImportantMessage "====== gocyclo"
gocyclo -over 15 .

printImportantMessage "====== ineffassign"
ineffassign ./...

printImportantMessage "====== misspell"
misspell *


================================================
FILE: mongo/wuid/wuid.go
================================================
package wuid

import (
	"context"
	"errors"
	"github.com/edwingeng/slog"
	"github.com/edwingeng/wuid/internal"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"go.mongodb.org/mongo-driver/mongo/readconcern"
	"go.mongodb.org/mongo-driver/mongo/readpref"
	"go.mongodb.org/mongo-driver/mongo/writeconcern"
	"time"
)

// WUID is an extremely fast universal unique identifier generator.
type WUID struct {
	w *internal.WUID
}

// NewWUID creates a new WUID instance.
func NewWUID(name string, logger slog.Logger, opts ...Option) *WUID {
	return &WUID{w: internal.NewWUID(name, logger, opts...)}
}

// Next returns a unique identifier.
func (w *WUID) Next() int64 {
	return w.w.Next()
}

type NewClient func() (client *mongo.Client, autoDisconnect bool, err error)

// LoadH28FromMongo adds 1 to a specific number in MongoDB and fetches its new value.
// The new value is used as the high 28 bits of all generated numbers. In addition, all the
// arguments passed in are saved for future renewal.
func (w *WUID) LoadH28FromMongo(newClient NewClient, dbName, coll, docID string) error {
	if len(dbName) == 0 {
		return errors.New("dbName cannot be empty")
	}
	if len(coll) == 0 {
		return errors.New("coll cannot be empty")
	}
	if len(docID) == 0 {
		return errors.New("docID cannot be empty")
	}

	client, autoDisconnect, err := newClient()
	if err != nil {
		return err
	}
	defer func() {
		if autoDisconnect {
			ctx2, cancel2 := context.WithTimeout(context.Background(), time.Second*5)
			defer cancel2()
			_ = client.Disconnect(ctx2)
		}
	}()

	ctx1, cancel1 := context.WithTimeout(context.Background(), time.Second*5)
	defer cancel1()
	if err := client.Ping(ctx1, readpref.Primary()); err != nil {
		return err
	}

	collOpts := &options.CollectionOptions{
		ReadConcern:    readconcern.Majority(),
		WriteConcern:   writeconcern.New(writeconcern.WMajority()),
		ReadPreference: readpref.Primary(),
	}

	var doc struct {
		N int32
	}

	filter := bson.D{
		{Key: "_id", Value: docID},
	}
	update := bson.D{
		{
			Key: "$inc",
			Value: bson.D{
				{Key: "n", Value: int32(1)},
			},
		},
	}

	var findOneAndUpdateOptions options.FindOneAndUpdateOptions
	findOneAndUpdateOptions.SetUpsert(true).SetReturnDocument(options.After)
	c := client.Database(dbName).Collection(coll, collOpts)
	err = c.FindOneAndUpdate(ctx1, filter, update, &findOneAndUpdateOptions).Decode(&doc)
	if err != nil {
		return err
	}
	h28 := int64(doc.N)
	if err = w.w.VerifyH28(h28); err != nil {
		return err
	}

	w.w.Reset(h28 << 36)
	w.w.Logger.Infof("<wuid> new h28: %d. name: %s", h28, w.w.Name)

	w.w.Lock()
	defer w.w.Unlock()

	if w.w.Renew != nil {
		return nil
	}
	w.w.Renew = func() error {
		return w.LoadH28FromMongo(newClient, dbName, coll, docID)
	}

	return nil
}

// RenewNow reacquires the high 28 bits immediately.
func (w *WUID) RenewNow() error {
	return w.w.RenewNow()
}

type Option = internal.Option

// WithH28Verifier adds an extra verifier for the high 28 bits.
func WithH28Verifier(cb func(h28 int64) error) Option {
	return internal.WithH28Verifier(cb)
}

// WithSection brands a section ID on each generated number. A section ID must be in between [0, 7].
func WithSection(section int8) Option {
	return internal.WithSection(section)
}

// WithStep sets the step and the floor for each generated number.
func WithStep(step int64, floor int64) Option {
	return internal.WithStep(step, floor)
}

// WithObfuscation enables number obfuscation.
func WithObfuscation(seed int) Option {
	return internal.WithObfuscation(seed)
}


================================================
FILE: mongo/wuid/wuid_test.go
================================================
package wuid

import (
	"context"
	"errors"
	"fmt"
	"github.com/edwingeng/slog"
	"github.com/edwingeng/wuid/internal"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"math/rand"
	"strings"
	"sync/atomic"
	"testing"
	"time"
)

var (
	dumb = slog.NewDumbLogger()
)

var (
	cfg struct {
		addr   string
		dbName string
		coll   string
		docID  string
	}
)

func init() {
	cfg.addr = "127.0.0.1:27017"
	cfg.dbName = "test"
	cfg.coll = "wuid"
	cfg.docID = "default"
}

func connectMongodb() (*mongo.Client, error) {
	ctx1, cancel1 := context.WithTimeout(context.Background(), time.Second*3)
	defer cancel1()
	uri := fmt.Sprintf("mongodb://%s", cfg.addr)
	return mongo.Connect(ctx1, options.Client().ApplyURI(uri))
}

func TestWUID_LoadH28FromMongo(t *testing.T) {
	newClient := func() (*mongo.Client, bool, error) {
		client, err := connectMongodb()
		return client, true, err
	}

	w := NewWUID(cfg.docID, dumb)
	err := w.LoadH28FromMongo(newClient, cfg.dbName, cfg.coll, cfg.docID)
	if err != nil {
		t.Fatal(err)
	}

	initial := atomic.LoadInt64(&w.w.N)
	for i := 1; i < 100; i++ {
		if err := w.RenewNow(); err != nil {
			t.Fatal(err)
		}
		expected := ((initial >> 36) + int64(i)) << 36
		if atomic.LoadInt64(&w.w.N) != expected {
			t.Fatalf("w.w.N is %d, while it should be %d. i: %d", atomic.LoadInt64(&w.w.N), expected, i)
		}
		n := rand.Intn(10)
		for j := 0; j < n; j++ {
			w.Next()
		}
	}
}

func TestWUID_LoadH28FromMongo_Error(t *testing.T) {
	w := NewWUID(cfg.docID, dumb)
	if w.LoadH28FromMongo(nil, "", cfg.coll, cfg.docID) == nil {
		t.Fatal("dbName is not properly checked")
	}
	if w.LoadH28FromMongo(nil, cfg.dbName, "", cfg.docID) == nil {
		t.Fatal("coll is not properly checked")
	}
	if w.LoadH28FromMongo(nil, cfg.dbName, cfg.coll, "") == nil {
		t.Fatal("docID is not properly checked")
	}

	newErrorClient := func() (*mongo.Client, bool, error) {
		return nil, true, errors.New("beta")
	}
	if w.LoadH28FromMongo(newErrorClient, cfg.dbName, cfg.coll, cfg.docID) == nil {
		t.Fatal(`w.LoadH28FromMongo(newErrorClient, cfg.dbName, cfg.coll, cfg.docID) == nil`)
	}
}

func waitUntilNumRenewedReaches(t *testing.T, w *WUID, expected int64) {
	t.Helper()
	startTime := time.Now()
	for time.Since(startTime) < time.Second*3 {
		if atomic.LoadInt64(&w.w.Stats.NumRenewed) == expected {
			return
		}
		time.Sleep(time.Millisecond * 10)
	}
	t.Fatal("timeout")
}

func TestWUID_Renew(t *testing.T) {
	client, err := connectMongodb()
	if err != nil {
		t.Fatal(err)
	}
	newClient := func() (*mongo.Client, bool, error) {
		return client, false, err
	}

	w := NewWUID(cfg.docID, slog.NewScavenger())
	err = w.LoadH28FromMongo(newClient, cfg.dbName, cfg.coll, cfg.docID)
	if err != nil {
		t.Fatal(err)
	}

	h28 := atomic.LoadInt64(&w.w.N) >> 36
	atomic.StoreInt64(&w.w.N, (h28<<36)|internal.Bye)
	n1a := w.Next()
	if n1a>>36 != h28 {
		t.Fatal(`n1a>>36 != h28`)
	}

	waitUntilNumRenewedReaches(t, w, 1)
	n1b := w.Next()
	if n1b != (h28+1)<<36+1 {
		t.Fatal(`n1b != (h28+1)<<36+1`)
	}

	atomic.StoreInt64(&w.w.N, ((h28+1)<<36)|internal.Bye)
	n2a := w.Next()
	if n2a>>36 != h28+1 {
		t.Fatal(`n2a>>36 != h28+1`)
	}

	waitUntilNumRenewedReaches(t, w, 2)
	n2b := w.Next()
	if n2b != (h28+2)<<36+1 {
		t.Fatal(`n2b != (h28+2)<<36+1`)
	}

	atomic.StoreInt64(&w.w.N, ((h28+2)<<36)|internal.Bye)
	n3a := w.Next()
	if n3a>>36 != h28+2 {
		t.Fatal(`n3a>>36 != h28+2`)
	}

	waitUntilNumRenewedReaches(t, w, 3)
	n3b := w.Next()
	if n3b != (h28+3)<<36+1 {
		t.Fatal(`n3b != (h28+3)<<36+1`)
	}

	atomic.StoreInt64(&w.w.N, ((h28+2)<<36)+internal.Bye+1)
	for i := 0; i < 100; i++ {
		w.Next()
	}
	if atomic.LoadInt64(&w.w.Stats.NumRenewAttempts) != 3 {
		t.Fatal(`atomic.LoadInt64(&w.w.Stats.NumRenewAttempts) != 3`)
	}

	var num int
	sc := w.w.Logger.(*slog.Scavenger)
	sc.Filter(func(level, msg string) bool {
		if level == slog.LevelInfo && strings.Contains(msg, "renew succeeded") {
			num++
		}
		return true
	})
	if num != 3 {
		t.Fatal(`num != 3`)
	}
}

func Example() {
	newClient := func() (*mongo.Client, bool, error) {
		var client *mongo.Client
		// ...
		return client, true, nil
	}

	// Setup
	w := NewWUID("alpha", nil)
	err := w.LoadH28FromMongo(newClient, "test", "wuid", "default")
	if err != nil {
		panic(err)
	}

	// Generate
	for i := 0; i < 10; i++ {
		fmt.Printf("%#016x\n", w.Next())
	}
}


================================================
FILE: mysql/db.sql
================================================
CREATE DATABASE IF NOT EXISTS test;

use test;

CREATE TABLE IF NOT EXISTS `wuid` (
    `h` int(10) NOT NULL AUTO_INCREMENT,
    `x` tinyint(4) NOT NULL DEFAULT '0',
    PRIMARY KEY (`x`),
    UNIQUE KEY `h` (`h`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


================================================
FILE: mysql/docker-mysql-client.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

docker run -it --rm mysql mysql -h host.docker.internal -u root -phello test


================================================
FILE: mysql/docker-mysql-server.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

docker run --name mysql-server -p 3306:3306 -e MYSQL_ROOT_PASSWORD=hello -d mysql
[[ $? -ne 0 ]] && exit 1

printImportantMessage "It may take quite a few seconds to get ready."
for ((i=0;i<1000;i++)); do
    docker run -it --rm mysql mysqladmin ping -h host.docker.internal --silent
    [[ $? -eq 0 ]] && echo "Ready." && break
    echo "Waiting $((i+1))..."
    sleep 1
done

sleep 1
docker run -v `pwd`/db.sql:/tmp/db.sql -it --rm mysql /bin/bash -c 'cat /tmp/db.sql | mysql -h host.docker.internal -u root -phello'
[[ $? -ne 0 ]] && exit 1

echo "Job done."


================================================
FILE: mysql/wuid/coverage.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

go test -cover -coverprofile=c.out -v "$@" && go tool cover -html=c.out


================================================
FILE: mysql/wuid/vet.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

printImportantMessage "====== gofmt"
gofmt -w .

printImportantMessage "====== go vet"
go vet ./...

printImportantMessage "====== gocyclo"
gocyclo -over 15 .

printImportantMessage "====== ineffassign"
ineffassign ./...

printImportantMessage "====== misspell"
misspell *


================================================
FILE: mysql/wuid/wuid.go
================================================
package wuid

import (
	"database/sql"
	"errors"
	"fmt"
	"github.com/edwingeng/slog"
	"github.com/edwingeng/wuid/internal"
	_ "github.com/go-sql-driver/mysql"
)

// WUID is an extremely fast universal unique identifier generator.
type WUID struct {
	w *internal.WUID
}

// NewWUID creates a new WUID instance.
func NewWUID(name string, logger slog.Logger, opts ...Option) *WUID {
	return &WUID{w: internal.NewWUID(name, logger, opts...)}
}

// Next returns a unique identifier.
func (w *WUID) Next() int64 {
	return w.w.Next()
}

type OpenDB func() (client *sql.DB, autoClose bool, err error)

// LoadH28FromMysql adds 1 to a specific number in MySQL and fetches its new value.
// The new value is used as the high 28 bits of all generated numbers. In addition, all the
// arguments passed in are saved for future renewal.
func (w *WUID) LoadH28FromMysql(openDB OpenDB, table string) error {
	if len(table) == 0 {
		return errors.New("table cannot be empty")
	}

	db, autoClose, err := openDB()
	if err != nil {
		return err
	}
	defer func() {
		if autoClose {
			_ = db.Close()
		}
	}()

	result, err := db.Exec(fmt.Sprintf("REPLACE INTO %s (x) VALUES (0)", table))
	if err != nil {
		return err
	}
	h28, err := result.LastInsertId()
	if err != nil {
		return err
	}
	if err = w.w.VerifyH28(h28); err != nil {
		return err
	}

	w.w.Reset(h28 << 36)
	w.w.Logger.Infof("<wuid> new h28: %d. name: %s", h28, w.w.Name)

	w.w.Lock()
	defer w.w.Unlock()

	if w.w.Renew != nil {
		return nil
	}
	w.w.Renew = func() error {
		return w.LoadH28FromMysql(openDB, table)
	}

	return nil
}

// RenewNow reacquires the high 28 bits immediately.
func (w *WUID) RenewNow() error {
	return w.w.RenewNow()
}

type Option = internal.Option

// WithH28Verifier adds an extra verifier for the high 28 bits.
func WithH28Verifier(cb func(h28 int64) error) Option {
	return internal.WithH28Verifier(cb)
}

// WithSection brands a section ID on each generated number. A section ID must be in between [0, 7].
func WithSection(section int8) Option {
	return internal.WithSection(section)
}

// WithStep sets the step and the floor for each generated number.
func WithStep(step int64, floor int64) Option {
	return internal.WithStep(step, floor)
}

// WithObfuscation enables number obfuscation.
func WithObfuscation(seed int) Option {
	return internal.WithObfuscation(seed)
}


================================================
FILE: mysql/wuid/wuid_test.go
================================================
package wuid

import (
	"database/sql"
	"errors"
	"fmt"
	"github.com/edwingeng/slog"
	"github.com/edwingeng/wuid/internal"
	_ "github.com/go-sql-driver/mysql"
	"math/rand"
	"strings"
	"sync/atomic"
	"testing"
	"time"
)

var (
	dumb = slog.NewDumbLogger()
)

var (
	cfg struct {
		addr   string
		user   string
		pass   string
		dbName string
		table  string
	}
)

func init() {
	cfg.addr = "127.0.0.1:3306"
	cfg.user = "root"
	cfg.pass = "hello"
	cfg.dbName = "test"
	cfg.table = "wuid"
}

func connect() (*sql.DB, error) {
	dsn := cfg.user
	if len(cfg.pass) > 0 {
		dsn += ":" + cfg.pass
	}
	dsn += "@tcp(" + cfg.addr + ")/" + cfg.dbName
	return sql.Open("mysql", dsn)
}

func TestWUID_LoadH28FromMysql(t *testing.T) {
	openDB := func() (*sql.DB, bool, error) {
		db, err := connect()
		return db, true, err
	}
	w := NewWUID("alpha", dumb)
	err := w.LoadH28FromMysql(openDB, cfg.table)
	if err != nil {
		t.Fatal(err)
	}

	initial := atomic.LoadInt64(&w.w.N)
	for i := 1; i < 100; i++ {
		if err := w.RenewNow(); err != nil {
			t.Fatal(err)
		}
		expected := ((initial >> 36) + int64(i)) << 36
		if atomic.LoadInt64(&w.w.N) != expected {
			t.Fatalf("w.w.N is %d, while it should be %d. i: %d", atomic.LoadInt64(&w.w.N), expected, i)
		}
		n := rand.Intn(10)
		for j := 0; j < n; j++ {
			w.Next()
		}
	}
}

func TestWUID_LoadH28FromMysql_Error(t *testing.T) {
	w := NewWUID("alpha", dumb)
	if w.LoadH28FromMysql(nil, "") == nil {
		t.Fatal("table is not properly checked")
	}

	newErrorDB := func() (client *sql.DB, autoClose bool, err error) {
		return nil, true, errors.New("beta")
	}
	if w.LoadH28FromMysql(newErrorDB, "beta") == nil {
		t.Fatal(`w.LoadH28FromMysql(newErrorDB, "beta") == nil`)
	}
}

func waitUntilNumRenewedReaches(t *testing.T, w *WUID, expected int64) {
	t.Helper()
	startTime := time.Now()
	for time.Since(startTime) < time.Second*3 {
		if atomic.LoadInt64(&w.w.Stats.NumRenewed) == expected {
			return
		}
		time.Sleep(time.Millisecond * 10)
	}
	t.Fatal("timeout")
}

func TestWUID_Next_Renew(t *testing.T) {
	db, err := connect()
	if err != nil {
		t.Fatal(err)
	}
	openDB := func() (*sql.DB, bool, error) {
		return db, false, err
	}

	w := NewWUID("alpha", slog.NewScavenger())
	err = w.LoadH28FromMysql(openDB, cfg.table)
	if err != nil {
		t.Fatal(err)
	}

	h28 := atomic.LoadInt64(&w.w.N) >> 36
	atomic.StoreInt64(&w.w.N, (h28<<36)|internal.Bye)
	n1a := w.Next()
	if n1a>>36 != h28 {
		t.Fatal(`n1a>>36 != h28`)
	}

	waitUntilNumRenewedReaches(t, w, 1)
	n1b := w.Next()
	if n1b != (h28+1)<<36+1 {
		t.Fatal(`n1b != (h28+1)<<36+1`)
	}

	atomic.StoreInt64(&w.w.N, ((h28+1)<<36)|internal.Bye)
	n2a := w.Next()
	if n2a>>36 != h28+1 {
		t.Fatal(`n2a>>36 != h28+1`)
	}

	waitUntilNumRenewedReaches(t, w, 2)
	n2b := w.Next()
	if n2b != (h28+2)<<36+1 {
		t.Fatal(`n2b != (h28+2)<<36+1`)
	}

	atomic.StoreInt64(&w.w.N, ((h28+2)<<36)|internal.Bye)
	n3a := w.Next()
	if n3a>>36 != h28+2 {
		t.Fatal(`n3a>>36 != h28+2`)
	}

	waitUntilNumRenewedReaches(t, w, 3)
	n3b := w.Next()
	if n3b != (h28+3)<<36+1 {
		t.Fatal(`n3b != (h28+3)<<36+1`)
	}

	atomic.StoreInt64(&w.w.N, ((h28+2)<<36)+internal.Bye+1)
	for i := 0; i < 100; i++ {
		w.Next()
	}
	if atomic.LoadInt64(&w.w.Stats.NumRenewAttempts) != 3 {
		t.Fatal(`atomic.LoadInt64(&w.w.Stats.NumRenewAttempts) != 3`)
	}

	var num int
	sc := w.w.Logger.(*slog.Scavenger)
	sc.Filter(func(level, msg string) bool {
		if level == slog.LevelInfo && strings.Contains(msg, "renew succeeded") {
			num++
		}
		return true
	})
	if num != 3 {
		t.Fatal(`num != 3`)
	}
}

func Example() {
	openDB := func() (*sql.DB, bool, error) {
		var db *sql.DB
		// ...
		return db, true, nil
	}

	// Setup
	w := NewWUID("alpha", nil)
	err := w.LoadH28FromMysql(openDB, "wuid")
	if err != nil {
		panic(err)
	}

	// Generate
	for i := 0; i < 10; i++ {
		fmt.Printf("%#016x\n", w.Next())
	}
}


================================================
FILE: redis/docker-redis-client.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

docker run -it --rm redis redis-cli -h host.docker.internal


================================================
FILE: redis/docker-redis-server.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

docker run --name redis-server -d -p 6379-6383:6379 redis


================================================
FILE: redis/v8/wuid/coverage.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

go test -cover -coverprofile=c.out -v "$@" && go tool cover -html=c.out


================================================
FILE: redis/v8/wuid/vet.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

printImportantMessage "====== gofmt"
gofmt -w .

printImportantMessage "====== go vet"
go vet ./...

printImportantMessage "====== gocyclo"
gocyclo -over 15 .

printImportantMessage "====== ineffassign"
ineffassign ./...

printImportantMessage "====== misspell"
misspell *


================================================
FILE: redis/v8/wuid/wuid.go
================================================
package wuid

import (
	"context"
	"errors"
	"github.com/edwingeng/slog"
	"github.com/edwingeng/wuid/internal"
	"github.com/go-redis/redis/v8"
	"time"
)

// WUID is an extremely fast universal unique identifier generator.
type WUID struct {
	w *internal.WUID
}

// NewWUID creates a new WUID instance.
func NewWUID(name string, logger slog.Logger, opts ...Option) *WUID {
	return &WUID{w: internal.NewWUID(name, logger, opts...)}
}

// Next returns a unique identifier.
func (w *WUID) Next() int64 {
	return w.w.Next()
}

type NewClient func() (client redis.UniversalClient, autoClose bool, err error)

// LoadH28FromRedis adds 1 to a specific number in Redis and fetches its new value.
// The new value is used as the high 28 bits of all generated numbers. In addition, all the
// arguments passed in are saved for future renewal.
func (w *WUID) LoadH28FromRedis(newClient NewClient, key string) error {
	if len(key) == 0 {
		return errors.New("key cannot be empty")
	}

	client, autoClose, err := newClient()
	if err != nil {
		return err
	}
	defer func() {
		if autoClose {
			_ = client.Close()
		}
	}()

	ctx1, cancel1 := context.WithTimeout(context.Background(), time.Second*5)
	defer cancel1()
	h28, err := client.Incr(ctx1, key).Result()
	if err != nil {
		return err
	}
	if err = w.w.VerifyH28(h28); err != nil {
		return err
	}

	w.w.Reset(h28 << 36)
	w.w.Logger.Infof("<wuid> new h28: %d. name: %s", h28, w.w.Name)

	w.w.Lock()
	defer w.w.Unlock()

	if w.w.Renew != nil {
		return nil
	}
	w.w.Renew = func() error {
		return w.LoadH28FromRedis(newClient, key)
	}

	return nil
}

// RenewNow reacquires the high 28 bits immediately.
func (w *WUID) RenewNow() error {
	return w.w.RenewNow()
}

type Option = internal.Option

// WithH28Verifier adds an extra verifier for the high 28 bits.
func WithH28Verifier(cb func(h28 int64) error) Option {
	return internal.WithH28Verifier(cb)
}

// WithSection brands a section ID on each generated number. A section ID must be in between [0, 7].
func WithSection(section int8) Option {
	return internal.WithSection(section)
}

// WithStep sets the step and the floor for each generated number.
func WithStep(step int64, floor int64) Option {
	return internal.WithStep(step, floor)
}

// WithObfuscation enables number obfuscation.
func WithObfuscation(seed int) Option {
	return internal.WithObfuscation(seed)
}


================================================
FILE: redis/v8/wuid/wuid_test.go
================================================
package wuid

import (
	"errors"
	"flag"
	"fmt"
	"github.com/edwingeng/slog"
	"github.com/edwingeng/wuid/internal"
	"github.com/go-redis/redis/v8"
	"math/rand"
	"strings"
	"sync/atomic"
	"testing"
	"time"
)

var redisCluster = flag.Bool("cluster", false, "")

var (
	dumb = slog.NewDumbLogger()
)

var (
	cfg struct {
		addrs    []string
		password string
		key      string
	}
)

func init() {
	cfg.addrs = []string{"127.0.0.1:6379", "127.0.0.1:6380", "127.0.0.1:6381"}
	cfg.key = "v8:wuid"
}

func connect() redis.UniversalClient {
	if *redisCluster {
		return redis.NewClusterClient(&redis.ClusterOptions{
			Addrs:    cfg.addrs,
			Password: cfg.password,
		})
	} else {
		return redis.NewClient(&redis.Options{
			Addr:     cfg.addrs[0],
			Password: cfg.password,
		})
	}
}

func TestWUID_LoadH28FromRedis(t *testing.T) {
	newClient := func() (redis.UniversalClient, bool, error) {
		return connect(), true, nil
	}
	w := NewWUID("alpha", dumb)
	err := w.LoadH28FromRedis(newClient, cfg.key)
	if err != nil {
		t.Fatal(err)
	}

	initial := atomic.LoadInt64(&w.w.N)
	for i := 1; i < 100; i++ {
		if err := w.RenewNow(); err != nil {
			t.Fatal(err)
		}
		expected := ((initial >> 36) + int64(i)) << 36
		if atomic.LoadInt64(&w.w.N) != expected {
			t.Fatalf("w.w.N is %d, while it should be %d. i: %d", atomic.LoadInt64(&w.w.N), expected, i)
		}
		n := rand.Intn(10)
		for j := 0; j < n; j++ {
			w.Next()
		}
	}
}

func TestWUID_LoadH28FromRedis_Error(t *testing.T) {
	w := NewWUID("alpha", dumb)
	if w.LoadH28FromRedis(nil, "") == nil {
		t.Fatal("key is not properly checked")
	}

	newErrorClient := func() (redis.UniversalClient, bool, error) {
		return nil, true, errors.New("beta")
	}
	if w.LoadH28FromRedis(newErrorClient, "beta") == nil {
		t.Fatal(`w.LoadH28FromRedis(newErrorClient, "beta") == nil`)
	}
}

func waitUntilNumRenewedReaches(t *testing.T, w *WUID, expected int64) {
	t.Helper()
	startTime := time.Now()
	for time.Since(startTime) < time.Second*3 {
		if atomic.LoadInt64(&w.w.Stats.NumRenewed) == expected {
			return
		}
		time.Sleep(time.Millisecond * 10)
	}
	t.Fatal("timeout")
}

func TestWUID_Next_Renew(t *testing.T) {
	client := connect()
	newClient := func() (redis.UniversalClient, bool, error) {
		return client, false, nil
	}

	w := NewWUID("alpha", slog.NewScavenger())
	err := w.LoadH28FromRedis(newClient, cfg.key)
	if err != nil {
		t.Fatal(err)
	}

	h28 := atomic.LoadInt64(&w.w.N) >> 36
	atomic.StoreInt64(&w.w.N, (h28<<36)|internal.Bye)
	n1a := w.Next()
	if n1a>>36 != h28 {
		t.Fatal(`n1a>>36 != h28`)
	}

	waitUntilNumRenewedReaches(t, w, 1)
	n1b := w.Next()
	if n1b != (h28+1)<<36+1 {
		t.Fatal(`n1b != (h28+1)<<36+1`)
	}

	atomic.StoreInt64(&w.w.N, ((h28+1)<<36)|internal.Bye)
	n2a := w.Next()
	if n2a>>36 != h28+1 {
		t.Fatal(`n2a>>36 != h28+1`)
	}

	waitUntilNumRenewedReaches(t, w, 2)
	n2b := w.Next()
	if n2b != (h28+2)<<36+1 {
		t.Fatal(`n2b != (h28+2)<<36+1`)
	}

	atomic.StoreInt64(&w.w.N, ((h28+2)<<36)|internal.Bye)
	n3a := w.Next()
	if n3a>>36 != h28+2 {
		t.Fatal(`n3a>>36 != h28+2`)
	}

	waitUntilNumRenewedReaches(t, w, 3)
	n3b := w.Next()
	if n3b != (h28+3)<<36+1 {
		t.Fatal(`n3b != (h28+3)<<36+1`)
	}

	atomic.StoreInt64(&w.w.N, ((h28+2)<<36)+internal.Bye+1)
	for i := 0; i < 100; i++ {
		w.Next()
	}
	if atomic.LoadInt64(&w.w.Stats.NumRenewAttempts) != 3 {
		t.Fatal(`atomic.LoadInt64(&w.w.Stats.NumRenewAttempts) != 3`)
	}

	var num int
	sc := w.w.Logger.(*slog.Scavenger)
	sc.Filter(func(level, msg string) bool {
		if level == slog.LevelInfo && strings.Contains(msg, "renew succeeded") {
			num++
		}
		return true
	})
	if num != 3 {
		t.Fatal(`num != 3`)
	}
}

func Example() {
	newClient := func() (redis.UniversalClient, bool, error) {
		var client redis.UniversalClient
		// ...
		return client, true, nil
	}

	// Setup
	w := NewWUID("alpha", nil)
	err := w.LoadH28FromRedis(newClient, "wuid")
	if err != nil {
		panic(err)
	}

	// Generate
	for i := 0; i < 10; i++ {
		fmt.Printf("%#016x\n", w.Next())
	}
}


================================================
FILE: redis/wuid/coverage.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

go test -cover -coverprofile=c.out -v "$@" && go tool cover -html=c.out


================================================
FILE: redis/wuid/vet.sh
================================================
#!/usr/bin/env bash

[[ "$TRACE" ]] && set -x
pushd `dirname "$0"` > /dev/null
trap __EXIT EXIT

colorful=false
tput setaf 7 > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
    colorful=true
fi

function __EXIT() {
    popd > /dev/null
}

function printError() {
    $colorful && tput setaf 1
    >&2 echo "Error: $@"
    $colorful && tput setaf 7
}

function printImportantMessage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

function printUsage() {
    $colorful && tput setaf 3
    >&2 echo "$@"
    $colorful && tput setaf 7
}

printImportantMessage "====== gofmt"
gofmt -w .

printImportantMessage "====== go vet"
go vet ./...

printImportantMessage "====== gocyclo"
gocyclo -over 15 .

printImportantMessage "====== ineffassign"
ineffassign ./...

printImportantMessage "====== misspell"
misspell *


================================================
FILE: redis/wuid/wuid.go
================================================
package wuid

import (
	"errors"
	"github.com/edwingeng/slog"
	"github.com/edwingeng/wuid/internal"
	"github.com/go-redis/redis"
)

// WUID is an extremely fast universal unique identifier generator.
type WUID struct {
	w *internal.WUID
}

// NewWUID creates a new WUID instance.
func NewWUID(name string, logger slog.Logger, opts ...Option) *WUID {
	return &WUID{w: internal.NewWUID(name, logger, opts...)}
}

// Next returns a unique identifier.
func (w *WUID) Next() int64 {
	return w.w.Next()
}

type NewClient func() (client redis.UniversalClient, autoClose bool, err error)

// LoadH28FromRedis adds 1 to a specific number in Redis and fetches its new value.
// The new value is used as the high 28 bits of all generated numbers. In addition, all the
// arguments passed in are saved for future renewal.
func (w *WUID) LoadH28FromRedis(newClient NewClient, key string) error {
	if len(key) == 0 {
		return errors.New("key cannot be empty")
	}

	client, autoClose, err := newClient()
	if err != nil {
		return err
	}
	defer func() {
		if autoClose {
			_ = client.Close()
		}
	}()

	h28, err := client.Incr(key).Result()
	if err != nil {
		return err
	}
	if err = w.w.VerifyH28(h28); err != nil {
		return err
	}

	w.w.Reset(h28 << 36)
	w.w.Logger.Infof("<wuid> new h28: %d. name: %s", h28, w.w.Name)

	w.w.Lock()
	defer w.w.Unlock()

	if w.w.Renew != nil {
		return nil
	}
	w.w.Renew = func() error {
		return w.LoadH28FromRedis(newClient, key)
	}

	return nil
}

// RenewNow reacquires the high 28 bits immediately.
func (w *WUID) RenewNow() error {
	return w.w.RenewNow()
}

type Option = internal.Option

// WithH28Verifier adds an extra verifier for the high 28 bits.
func WithH28Verifier(cb func(h28 int64) error) Option {
	return internal.WithH28Verifier(cb)
}

// WithSection brands a section ID on each generated number. A section ID must be in between [0, 7].
func WithSection(section int8) Option {
	return internal.WithSection(section)
}

// WithStep sets the step and the floor for each generated number.
func WithStep(step int64, floor int64) Option {
	return internal.WithStep(step, floor)
}

// WithObfuscation enables number obfuscation.
func WithObfuscation(seed int) Option {
	return internal.WithObfuscation(seed)
}


================================================
FILE: redis/wuid/wuid_test.go
================================================
package wuid

import (
	"errors"
	"flag"
	"fmt"
	"github.com/edwingeng/slog"
	"github.com/edwingeng/wuid/internal"
	"github.com/go-redis/redis"
	"math/rand"
	"strings"
	"sync/atomic"
	"testing"
	"time"
)

var redisCluster = flag.Bool("cluster", false, "")

var (
	dumb = slog.NewDumbLogger()
)

var (
	cfg struct {
		addrs    []string
		password string
		key      string
	}
)

func init() {
	cfg.addrs = []string{"127.0.0.1:6379", "127.0.0.1:6380", "127.0.0.1:6381"}
	cfg.key = "wuid"
}

func connect() redis.UniversalClient {
	if *redisCluster {
		return redis.NewClusterClient(&redis.ClusterOptions{
			Addrs:    cfg.addrs,
			Password: cfg.password,
		})
	} else {
		return redis.NewClient(&redis.Options{
			Addr:     cfg.addrs[0],
			Password: cfg.password,
		})
	}
}

func TestWUID_LoadH28FromRedis(t *testing.T) {
	newClient := func() (redis.UniversalClient, bool, error) {
		return connect(), true, nil
	}
	w := NewWUID("alpha", dumb)
	err := w.LoadH28FromRedis(newClient, cfg.key)
	if err != nil {
		t.Fatal(err)
	}

	initial := atomic.LoadInt64(&w.w.N)
	for i := 1; i < 100; i++ {
		if err := w.RenewNow(); err != nil {
			t.Fatal(err)
		}
		expected := ((initial >> 36) + int64(i)) << 36
		if atomic.LoadInt64(&w.w.N) != expected {
			t.Fatalf("w.w.N is %d, while it should be %d. i: %d", atomic.LoadInt64(&w.w.N), expected, i)
		}
		n := rand.Intn(10)
		for j := 0; j < n; j++ {
			w.Next()
		}
	}
}

func TestWUID_LoadH28FromRedis_Error(t *testing.T) {
	w := NewWUID("alpha", dumb)
	if w.LoadH28FromRedis(nil, "") == nil {
		t.Fatal("key is not properly checked")
	}

	newErrorClient := func() (redis.UniversalClient, bool, error) {
		return nil, true, errors.New("beta")
	}
	if w.LoadH28FromRedis(newErrorClient, "beta") == nil {
		t.Fatal(`w.LoadH28FromRedis(newErrorClient, "beta") == nil`)
	}
}

func waitUntilNumRenewedReaches(t *testing.T, w *WUID, expected int64) {
	t.Helper()
	startTime := time.Now()
	for time.Since(startTime) < time.Second*3 {
		if atomic.LoadInt64(&w.w.Stats.NumRenewed) == expected {
			return
		}
		time.Sleep(time.Millisecond * 10)
	}
	t.Fatal("timeout")
}

func TestWUID_Next_Renew(t *testing.T) {
	client := connect()
	newClient := func() (redis.UniversalClient, bool, error) {
		return client, false, nil
	}

	w := NewWUID("alpha", slog.NewScavenger())
	err := w.LoadH28FromRedis(newClient, cfg.key)
	if err != nil {
		t.Fatal(err)
	}

	h28 := atomic.LoadInt64(&w.w.N) >> 36
	atomic.StoreInt64(&w.w.N, (h28<<36)|internal.Bye)
	n1a := w.Next()
	if n1a>>36 != h28 {
		t.Fatal(`n1a>>36 != h28`)
	}

	waitUntilNumRenewedReaches(t, w, 1)
	n1b := w.Next()
	if n1b != (h28+1)<<36+1 {
		t.Fatal(`n1b != (h28+1)<<36+1`)
	}

	atomic.StoreInt64(&w.w.N, ((h28+1)<<36)|internal.Bye)
	n2a := w.Next()
	if n2a>>36 != h28+1 {
		t.Fatal(`n2a>>36 != h28+1`)
	}

	waitUntilNumRenewedReaches(t, w, 2)
	n2b := w.Next()
	if n2b != (h28+2)<<36+1 {
		t.Fatal(`n2b != (h28+2)<<36+1`)
	}

	atomic.StoreInt64(&w.w.N, ((h28+2)<<36)|internal.Bye)
	n3a := w.Next()
	if n3a>>36 != h28+2 {
		t.Fatal(`n3a>>36 != h28+2`)
	}

	waitUntilNumRenewedReaches(t, w, 3)
	n3b := w.Next()
	if n3b != (h28+3)<<36+1 {
		t.Fatal(`n3b != (h28+3)<<36+1`)
	}

	atomic.StoreInt64(&w.w.N, ((h28+2)<<36)+internal.Bye+1)
	for i := 0; i < 100; i++ {
		w.Next()
	}
	if atomic.LoadInt64(&w.w.Stats.NumRenewAttempts) != 3 {
		t.Fatal(`atomic.LoadInt64(&w.w.Stats.NumRenewAttempts) != 3`)
	}

	var num int
	sc := w.w.Logger.(*slog.Scavenger)
	sc.Filter(func(level, msg string) bool {
		if level == slog.LevelInfo && strings.Contains(msg, "renew succeeded") {
			num++
		}
		return true
	})
	if num != 3 {
		t.Fatal(`num != 3`)
	}
}

func Example() {
	newClient := func() (redis.UniversalClient, bool, error) {
		var client redis.UniversalClient
		// ...
		return client, true, nil
	}

	// Setup
	w := NewWUID("alpha", nil)
	err := w.LoadH28FromRedis(newClient, "wuid")
	if err != nil {
		panic(err)
	}

	// Generate
	for i := 0; i < 10; i++ {
		fmt.Printf("%#016x\n", w.Next())
	}
}


================================================
FILE: wuid.go
================================================
package wuid

type WUID interface {
	Next() int64
}
Download .txt
gitextract_35st_wr2/

├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── callback/
│   └── wuid/
│       ├── coverage.sh
│       ├── vet.sh
│       ├── wuid.go
│       └── wuid_test.go
├── check.sh
├── go.mod
├── go.sum
├── internal/
│   ├── coverage.sh
│   ├── vet.sh
│   ├── wuid.go
│   └── wuid_test.go
├── mongo/
│   ├── docker-mongo-client.sh
│   ├── docker-mongo-server.sh
│   └── wuid/
│       ├── coverage.sh
│       ├── vet.sh
│       ├── wuid.go
│       └── wuid_test.go
├── mysql/
│   ├── db.sql
│   ├── docker-mysql-client.sh
│   ├── docker-mysql-server.sh
│   └── wuid/
│       ├── coverage.sh
│       ├── vet.sh
│       ├── wuid.go
│       └── wuid_test.go
├── redis/
│   ├── docker-redis-client.sh
│   ├── docker-redis-server.sh
│   ├── v8/
│   │   └── wuid/
│   │       ├── coverage.sh
│   │       ├── vet.sh
│   │       ├── wuid.go
│   │       └── wuid_test.go
│   └── wuid/
│       ├── coverage.sh
│       ├── vet.sh
│       ├── wuid.go
│       └── wuid_test.go
└── wuid.go
Download .txt
SYMBOL INDEX (121 symbols across 14 files)

FILE: callback/wuid/wuid.go
  type WUID (line 10) | type WUID struct
    method Next (line 20) | func (w *WUID) Next() int64 {
    method LoadH28WithCallback (line 28) | func (w *WUID) LoadH28WithCallback(cb H28Callback) error {
    method RenewNow (line 62) | func (w *WUID) RenewNow() error {
  function NewWUID (line 15) | func NewWUID(name string, logger slog.Logger, opts ...Option) *WUID {
  type H28Callback (line 24) | type H28Callback
  function WithH28Verifier (line 69) | func WithH28Verifier(cb func(h28 int64) error) Option {
  function WithSection (line 74) | func WithSection(section int8) Option {
  function WithStep (line 79) | func WithStep(step int64, floor int64) Option {
  function WithObfuscation (line 84) | func WithObfuscation(seed int) Option {

FILE: callback/wuid/wuid_test.go
  function TestWUID_LoadH28WithCallback_Error (line 19) | func TestWUID_LoadH28WithCallback_Error(t *testing.T) {
  function TestWUID_LoadH28WithCallback (line 41) | func TestWUID_LoadH28WithCallback(t *testing.T) {
  function TestWUID_LoadH28WithCallback_Section (line 74) | func TestWUID_LoadH28WithCallback_Section(t *testing.T) {
  function TestWUID_LoadH28WithCallback_Same (line 97) | func TestWUID_LoadH28WithCallback_Same(t *testing.T) {
  function waitUntilNumRenewedReaches (line 115) | func waitUntilNumRenewedReaches(t *testing.T, w *WUID, expected int64) {
  function TestWUID_Renew (line 127) | func TestWUID_Renew(t *testing.T) {
  function Example (line 194) | func Example() {

FILE: internal/wuid.go
  constant PanicValue (line 13) | PanicValue int64 = ((1 << 36) * 96 / 100) & ^1023
  constant CriticalValue (line 15) | CriticalValue int64 = ((1 << 36) * 80 / 100) & ^1023
  constant RenewIntervalMask (line 17) | RenewIntervalMask int64 = 0x20000000 - 1
  constant Bye (line 21) | Bye = ((CriticalValue + RenewIntervalMask) & ^RenewIntervalMask) - 1
  constant H28Mask (line 25) | H28Mask = 0x07FFFFFF << 36
  constant L36Mask (line 26) | L36Mask = 0x0FFFFFFFFF
  type WUID (line 29) | type WUID struct
    method Next (line 72) | func (w *WUID) Next() int64 {
    method RenewNow (line 123) | func (w *WUID) RenewNow() error {
    method Reset (line 130) | func (w *WUID) Reset(n int64) {
    method VerifyH28 (line 155) | func (w *WUID) VerifyH28(h28 int64) error {
  function NewWUID (line 53) | func NewWUID(name string, logger slog.Logger, opts ...Option) (w *WUID) {
  function renewImpl (line 104) | func renewImpl(w *WUID) {
  type Option (line 190) | type Option
  function WithH28Verifier (line 192) | func WithH28Verifier(cb func(h28 int64) error) Option {
  function WithSection (line 198) | func WithSection(section int8) Option {
  function WithStep (line 208) | func WithStep(step int64, floor int64) Option {
  function WithObfuscation (line 229) | func WithObfuscation(seed int) Option {

FILE: internal/wuid_test.go
  method Scavenger (line 15) | func (w *WUID) Scavenger() *slog.Scavenger {
  function TestWUID_Next (line 19) | func TestWUID_Next(t *testing.T) {
  function TestWUID_Next_Concurrent (line 33) | func TestWUID_Next_Concurrent(t *testing.T) {
  function TestWUID_Next_Panic (line 66) | func TestWUID_Next_Panic(t *testing.T) {
  function waitUntilNumRenewAttemptsReaches (line 92) | func waitUntilNumRenewAttemptsReaches(t *testing.T, w *WUID, expected in...
  function waitUntilNumRenewedReaches (line 104) | func waitUntilNumRenewedReaches(t *testing.T, w *WUID, expected int64) {
  function TestWUID_Renew (line 116) | func TestWUID_Renew(t *testing.T) {
  function TestWUID_Renew_Error (line 179) | func TestWUID_Renew_Error(t *testing.T) {
  function TestWUID_Renew_Panic (line 216) | func TestWUID_Renew_Panic(t *testing.T) {
  function TestWUID_Step (line 253) | func TestWUID_Step(t *testing.T) {
  function TestWUID_Floor (line 304) | func TestWUID_Floor(t *testing.T) {
  function TestWUID_VerifyH28 (line 354) | func TestWUID_VerifyH28(t *testing.T) {
  function TestWithSection_Panic (line 386) | func TestWithSection_Panic(t *testing.T) {
  function TestWithSection_Reset (line 400) | func TestWithSection_Reset(t *testing.T) {
  function TestWithH28Verifier (line 432) | func TestWithH28Verifier(t *testing.T) {
  function TestWithObfuscation (line 448) | func TestWithObfuscation(t *testing.T) {

FILE: mongo/wuid/wuid.go
  type WUID (line 18) | type WUID struct
    method Next (line 28) | func (w *WUID) Next() int64 {
    method LoadH28FromMongo (line 37) | func (w *WUID) LoadH28FromMongo(newClient NewClient, dbName, coll, doc...
    method RenewNow (line 117) | func (w *WUID) RenewNow() error {
  function NewWUID (line 23) | func NewWUID(name string, logger slog.Logger, opts ...Option) *WUID {
  type NewClient (line 32) | type NewClient
  function WithH28Verifier (line 124) | func WithH28Verifier(cb func(h28 int64) error) Option {
  function WithSection (line 129) | func WithSection(section int8) Option {
  function WithStep (line 134) | func WithStep(step int64, floor int64) Option {
  function WithObfuscation (line 139) | func WithObfuscation(seed int) Option {

FILE: mongo/wuid/wuid_test.go
  function init (line 31) | func init() {
  function connectMongodb (line 38) | func connectMongodb() (*mongo.Client, error) {
  function TestWUID_LoadH28FromMongo (line 45) | func TestWUID_LoadH28FromMongo(t *testing.T) {
  function TestWUID_LoadH28FromMongo_Error (line 73) | func TestWUID_LoadH28FromMongo_Error(t *testing.T) {
  function waitUntilNumRenewedReaches (line 93) | func waitUntilNumRenewedReaches(t *testing.T, w *WUID, expected int64) {
  function TestWUID_Renew (line 105) | func TestWUID_Renew(t *testing.T) {
  function Example (line 178) | func Example() {

FILE: mysql/db.sql
  type `wuid` (line 5) | CREATE TABLE IF NOT EXISTS `wuid` (

FILE: mysql/wuid/wuid.go
  type WUID (line 13) | type WUID struct
    method Next (line 23) | func (w *WUID) Next() int64 {
    method LoadH28FromMysql (line 32) | func (w *WUID) LoadH28FromMysql(openDB OpenDB, table string) error {
    method RenewNow (line 76) | func (w *WUID) RenewNow() error {
  function NewWUID (line 18) | func NewWUID(name string, logger slog.Logger, opts ...Option) *WUID {
  type OpenDB (line 27) | type OpenDB
  function WithH28Verifier (line 83) | func WithH28Verifier(cb func(h28 int64) error) Option {
  function WithSection (line 88) | func WithSection(section int8) Option {
  function WithStep (line 93) | func WithStep(step int64, floor int64) Option {
  function WithObfuscation (line 98) | func WithObfuscation(seed int) Option {

FILE: mysql/wuid/wuid_test.go
  function init (line 31) | func init() {
  function connect (line 39) | func connect() (*sql.DB, error) {
  function TestWUID_LoadH28FromMysql (line 48) | func TestWUID_LoadH28FromMysql(t *testing.T) {
  function TestWUID_LoadH28FromMysql_Error (line 75) | func TestWUID_LoadH28FromMysql_Error(t *testing.T) {
  function waitUntilNumRenewedReaches (line 89) | func waitUntilNumRenewedReaches(t *testing.T, w *WUID, expected int64) {
  function TestWUID_Next_Renew (line 101) | func TestWUID_Next_Renew(t *testing.T) {
  function Example (line 174) | func Example() {

FILE: redis/v8/wuid/wuid.go
  type WUID (line 13) | type WUID struct
    method Next (line 23) | func (w *WUID) Next() int64 {
    method LoadH28FromRedis (line 32) | func (w *WUID) LoadH28FromRedis(newClient NewClient, key string) error {
    method RenewNow (line 74) | func (w *WUID) RenewNow() error {
  function NewWUID (line 18) | func NewWUID(name string, logger slog.Logger, opts ...Option) *WUID {
  type NewClient (line 27) | type NewClient
  function WithH28Verifier (line 81) | func WithH28Verifier(cb func(h28 int64) error) Option {
  function WithSection (line 86) | func WithSection(section int8) Option {
  function WithStep (line 91) | func WithStep(step int64, floor int64) Option {
  function WithObfuscation (line 96) | func WithObfuscation(seed int) Option {

FILE: redis/v8/wuid/wuid_test.go
  function init (line 31) | func init() {
  function connect (line 36) | func connect() redis.UniversalClient {
  function TestWUID_LoadH28FromRedis (line 50) | func TestWUID_LoadH28FromRedis(t *testing.T) {
  function TestWUID_LoadH28FromRedis_Error (line 76) | func TestWUID_LoadH28FromRedis_Error(t *testing.T) {
  function waitUntilNumRenewedReaches (line 90) | func waitUntilNumRenewedReaches(t *testing.T, w *WUID, expected int64) {
  function TestWUID_Next_Renew (line 102) | func TestWUID_Next_Renew(t *testing.T) {
  function Example (line 172) | func Example() {

FILE: redis/wuid/wuid.go
  type WUID (line 11) | type WUID struct
    method Next (line 21) | func (w *WUID) Next() int64 {
    method LoadH28FromRedis (line 30) | func (w *WUID) LoadH28FromRedis(newClient NewClient, key string) error {
    method RenewNow (line 70) | func (w *WUID) RenewNow() error {
  function NewWUID (line 16) | func NewWUID(name string, logger slog.Logger, opts ...Option) *WUID {
  type NewClient (line 25) | type NewClient
  function WithH28Verifier (line 77) | func WithH28Verifier(cb func(h28 int64) error) Option {
  function WithSection (line 82) | func WithSection(section int8) Option {
  function WithStep (line 87) | func WithStep(step int64, floor int64) Option {
  function WithObfuscation (line 92) | func WithObfuscation(seed int) Option {

FILE: redis/wuid/wuid_test.go
  function init (line 31) | func init() {
  function connect (line 36) | func connect() redis.UniversalClient {
  function TestWUID_LoadH28FromRedis (line 50) | func TestWUID_LoadH28FromRedis(t *testing.T) {
  function TestWUID_LoadH28FromRedis_Error (line 76) | func TestWUID_LoadH28FromRedis_Error(t *testing.T) {
  function waitUntilNumRenewedReaches (line 90) | func waitUntilNumRenewedReaches(t *testing.T, w *WUID, expected int64) {
  function TestWUID_Next_Renew (line 102) | func TestWUID_Next_Renew(t *testing.T) {
  function Example (line 172) | func Example() {

FILE: wuid.go
  type WUID (line 3) | type WUID interface
Condensed preview — 39 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (88K chars).
[
  {
    "path": ".gitattributes",
    "chars": 20,
    "preview": "* text=auto eol=lf\n\n"
  },
  {
    "path": ".gitignore",
    "chars": 298,
    "preview": "# Binaries for programs and plugins\n*.exe\n*.dll\n*.so\n*.dylib\n\n# Test binary, build with `go test -c`\n*.test\n\n# Output of"
  },
  {
    "path": "LICENSE",
    "chars": 1515,
    "preview": "BSD 3-Clause License\n\nCopyright (c) 2018-2022, Edwin Geng\nAll rights reserved.\n\nRedistribution and use in source and bin"
  },
  {
    "path": "README.md",
    "chars": 4424,
    "preview": "# Overview\n- `WUID` is a universal unique identifier generator.\n- `WUID` is much faster than traditional UUID. Each `WUI"
  },
  {
    "path": "callback/wuid/coverage.sh",
    "chars": 637,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "callback/wuid/vet.sh",
    "chars": 838,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "callback/wuid/wuid.go",
    "chars": 1991,
    "preview": "package wuid\n\nimport (\n\t\"errors\"\n\t\"github.com/edwingeng/slog\"\n\t\"github.com/edwingeng/wuid/internal\"\n)\n\n// WUID is an ext"
  },
  {
    "path": "callback/wuid/wuid_test.go",
    "chars": 4623,
    "preview": "package wuid\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/edwingeng/slog\"\n\t\"github.com/edwingeng/wuid/internal\"\n\t\"math/rand\"\n"
  },
  {
    "path": "check.sh",
    "chars": 821,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "go.mod",
    "chars": 1213,
    "preview": "module github.com/edwingeng/wuid\n\ngo 1.18\n\nrequire (\n\tgithub.com/edwingeng/slog v0.0.0-20221027170832-482f0dfb6247\n\tgith"
  },
  {
    "path": "go.sum",
    "chars": 7970,
    "preview": "github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=\ngithub.com/cespare/xxhash/v2 v2.1.2 "
  },
  {
    "path": "internal/coverage.sh",
    "chars": 637,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "internal/vet.sh",
    "chars": 838,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "internal/wuid.go",
    "chars": 4827,
    "preview": "package internal\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/edwingeng/slog\"\n\t\"sync\"\n\t\"sync/atomic\"\n)\n\nconst (\n\t// PanicValu"
  },
  {
    "path": "internal/wuid_test.go",
    "chars": 11243,
    "preview": "package internal\n\nimport (\n\t\"errors\"\n\t\"github.com/edwingeng/slog\"\n\t\"math/rand\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\""
  },
  {
    "path": "mongo/docker-mongo-client.sh",
    "chars": 620,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "mongo/docker-mongo-server.sh",
    "chars": 620,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "mongo/wuid/coverage.sh",
    "chars": 637,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "mongo/wuid/vet.sh",
    "chars": 838,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "mongo/wuid/wuid.go",
    "chars": 3593,
    "preview": "package wuid\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"github.com/edwingeng/slog\"\n\t\"github.com/edwingeng/wuid/internal\"\n\t\"go.mong"
  },
  {
    "path": "mongo/wuid/wuid_test.go",
    "chars": 4344,
    "preview": "package wuid\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/edwingeng/slog\"\n\t\"github.com/edwingeng/wuid/internal\"\n\t\""
  },
  {
    "path": "mysql/db.sql",
    "chars": 254,
    "preview": "CREATE DATABASE IF NOT EXISTS test;\n\nuse test;\n\nCREATE TABLE IF NOT EXISTS `wuid` (\n    `h` int(10) NOT NULL AUTO_INCREM"
  },
  {
    "path": "mysql/docker-mysql-client.sh",
    "chars": 642,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "mysql/docker-mysql-server.sh",
    "chars": 1127,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "mysql/wuid/coverage.sh",
    "chars": 637,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "mysql/wuid/vet.sh",
    "chars": 838,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "mysql/wuid/wuid.go",
    "chars": 2349,
    "preview": "package wuid\n\nimport (\n\t\"database/sql\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/edwingeng/slog\"\n\t\"github.com/edwingeng/wuid/interna"
  },
  {
    "path": "mysql/wuid/wuid_test.go",
    "chars": 3838,
    "preview": "package wuid\n\nimport (\n\t\"database/sql\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/edwingeng/slog\"\n\t\"github.com/edwingeng/wuid/interna"
  },
  {
    "path": "redis/docker-redis-client.sh",
    "chars": 625,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "redis/docker-redis-server.sh",
    "chars": 623,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "redis/v8/wuid/coverage.sh",
    "chars": 637,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "redis/v8/wuid/vet.sh",
    "chars": 838,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "redis/v8/wuid/wuid.go",
    "chars": 2361,
    "preview": "package wuid\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"github.com/edwingeng/slog\"\n\t\"github.com/edwingeng/wuid/internal\"\n\t\"github."
  },
  {
    "path": "redis/v8/wuid/wuid_test.go",
    "chars": 3979,
    "preview": "package wuid\n\nimport (\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"github.com/edwingeng/slog\"\n\t\"github.com/edwingeng/wuid/internal\"\n\t\"git"
  },
  {
    "path": "redis/wuid/coverage.sh",
    "chars": 637,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "redis/wuid/vet.sh",
    "chars": 838,
    "preview": "#!/usr/bin/env bash\n\n[[ \"$TRACE\" ]] && set -x\npushd `dirname \"$0\"` > /dev/null\ntrap __EXIT EXIT\n\ncolorful=false\ntput set"
  },
  {
    "path": "redis/wuid/wuid.go",
    "chars": 2241,
    "preview": "package wuid\n\nimport (\n\t\"errors\"\n\t\"github.com/edwingeng/slog\"\n\t\"github.com/edwingeng/wuid/internal\"\n\t\"github.com/go-redi"
  },
  {
    "path": "redis/wuid/wuid_test.go",
    "chars": 3973,
    "preview": "package wuid\n\nimport (\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"github.com/edwingeng/slog\"\n\t\"github.com/edwingeng/wuid/internal\"\n\t\"git"
  },
  {
    "path": "wuid.go",
    "chars": 52,
    "preview": "package wuid\n\ntype WUID interface {\n\tNext() int64\n}\n"
  }
]

About this extraction

This page contains the full source code of the edwingeng/wuid GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 39 files (77.2 KB), approximately 29.0k tokens, and a symbol index with 121 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!