Various improvements.

This commit is contained in:
2026-02-21 00:34:57 +01:00
parent 8670c509e8
commit 09a1c8dd26
6 changed files with 160 additions and 11 deletions

View File

@@ -8,7 +8,8 @@ import (
)
const (
MaxIndex = block
MaxIndex = block
MaxRandomAttempts = 1024
letters = 26
numbers = 900 // 100999
@@ -23,9 +24,16 @@ var (
ErrNumberOutOfRange = errors.New("number out of range")
ErrInvalidChecksum = errors.New("invalid checksum")
ErrIndexOutOfRange = errors.New("index out of range")
ErrRandomGenerationFailed = errors.New("random code generation failed")
ErrRandomSourceFailed = errors.New("random source failed")
ErrNoAvailableIndex = errors.New("no available index found")
)
type RandomCodeOptions struct {
MaxAttempts int
IsInUse func(uint32) bool
RandomIndex func(max uint32) (uint32, error)
}
func Encode(code string) (uint32, error) {
// Expected format: L1L2L3-NNN-L4C => length 10, positions: 0,1,2,4,5,6,8,9
if len(code) != 10 || code[3] != '-' || code[7] != '-' {
@@ -103,15 +111,34 @@ func Decode(idx uint32) (string, error) {
}
func RandomCode(isInUse ...func(uint32) bool) (string, uint32, error) {
var inUse func(uint32) bool
options := RandomCodeOptions{}
if len(isInUse) > 0 {
inUse = isInUse[0]
options.IsInUse = isInUse[0]
}
for attempts := 0; attempts < 1024; attempts++ {
idx, err := randomUint32n(MaxIndex)
return RandomCodeWithOptions(options)
}
func RandomCodeWithOptions(options RandomCodeOptions) (string, uint32, error) {
maxAttempts := options.MaxAttempts
if maxAttempts <= 0 {
maxAttempts = MaxRandomAttempts
}
inUse := options.IsInUse
randomIndex := options.RandomIndex
if randomIndex == nil {
randomIndex = randomUint32n
}
for attempts := 0; attempts < maxAttempts; attempts++ {
idx, err := randomIndex(MaxIndex)
if err != nil {
return "", 0, err
return "", 0, fmt.Errorf("%w: %v", ErrRandomSourceFailed, err)
}
if idx >= MaxIndex {
return "", 0, fmt.Errorf("%w: index out of range", ErrRandomSourceFailed)
}
if inUse != nil && inUse(idx) {
@@ -129,7 +156,7 @@ func RandomCode(isInUse ...func(uint32) bool) (string, uint32, error) {
return "", 0, err
}
return "", 0, ErrRandomGenerationFailed
return "", 0, ErrNoAvailableIndex
}
func checksumLetter(idx uint32) byte {