refactor: rename options interface and move PRNG to generator

This commit is contained in:
Peter 2023-04-25 17:45:32 +02:00
parent 9bf6cb3539
commit 997460bbdc
No known key found for this signature in database
3 changed files with 57 additions and 47 deletions

8
api.go
View file

@ -1,9 +1,13 @@
package pwgen package pwgen
type GeneratorOption interface { type Int32n interface {
Int31n(n int32) int32
}
type GenerationOption interface {
ApplyToOptions(options *options) ApplyToOptions(options *options)
} }
type Generator interface { type Generator interface {
Generate(opts ...GeneratorOption) (string, error) Generate(opts ...GenerationOption) (string, error)
} }

View file

@ -2,8 +2,6 @@ package pwgen
import ( import (
"errors" "errors"
"math/rand"
"time"
) )
const ( const (
@ -13,50 +11,50 @@ const (
var ErrLengthOverflow = errors.New("length overflow") var ErrLengthOverflow = errors.New("length overflow")
type generatorOptionFunc func(options *options) type generationOptionFunc func(options *options)
func (f generatorOptionFunc) ApplyToOptions(options *options) { func (f generationOptionFunc) ApplyToOptions(options *options) {
f(options) f(options)
} }
func WithLength(length uint) GeneratorOption { func WithLength(length uint) GenerationOption {
return generatorOptionFunc(func(options *options) { return generationOptionFunc(func(options *options) {
options.Length = length options.Length = length
}) })
} }
func WithLetters(letters uint) GeneratorOption { func WithLetters(letters uint) GenerationOption {
return generatorOptionFunc(func(options *options) { return generationOptionFunc(func(options *options) {
options.Letters = letters options.Letters = letters
}) })
} }
func WithUppercase(uppercase uint) GeneratorOption { func WithUppercase(uppercase uint) GenerationOption {
return generatorOptionFunc(func(options *options) { return generationOptionFunc(func(options *options) {
options.Uppercase = uppercase options.Uppercase = uppercase
}) })
} }
func WithLowercase(lowercase uint) GeneratorOption { func WithLowercase(lowercase uint) GenerationOption {
return generatorOptionFunc(func(options *options) { return generationOptionFunc(func(options *options) {
options.Lowercase = lowercase options.Lowercase = lowercase
}) })
} }
func WithDigits(digits uint) GeneratorOption { func WithDigits(digits uint) GenerationOption {
return generatorOptionFunc(func(options *options) { return generationOptionFunc(func(options *options) {
options.Digits = digits options.Digits = digits
}) })
} }
func WithSpecials(specials uint) GeneratorOption { func WithSpecials(specials uint) GenerationOption {
return generatorOptionFunc(func(options *options) { return generationOptionFunc(func(options *options) {
options.Specials = specials options.Specials = specials
}) })
} }
func WithSpecialsAlphabet(specialsAlphabet string) GeneratorOption { func WithSpecialsAlphabet(specialsAlphabet string) GenerationOption {
return generatorOptionFunc(func(options *options) { return generationOptionFunc(func(options *options) {
if specialsAlphabet == "" { if specialsAlphabet == "" {
specialsAlphabet = DefaultSpecialsAlphabet specialsAlphabet = DefaultSpecialsAlphabet
} }
@ -64,15 +62,8 @@ func WithSpecialsAlphabet(specialsAlphabet string) GeneratorOption {
}) })
} }
func WithPRNG(prng Int32n) GeneratorOption { func defaultOptions(opts ...GenerationOption) *options {
return generatorOptionFunc(func(options *options) {
options.PRNG = prng
})
}
func defaultOptions(opts ...GeneratorOption) *options {
o := &options{ o := &options{
PRNG: rand.New(rand.NewSource(time.Now().Unix())),
Length: DefaultLength, Length: DefaultLength,
Letters: 0, Letters: 0,
Digits: 3, Digits: 3,
@ -89,12 +80,7 @@ func defaultOptions(opts ...GeneratorOption) *options {
return o return o
} }
type Int32n interface {
Int31n(n int32) int32
}
type options struct { type options struct {
PRNG Int32n
Length uint Length uint
Letters uint Letters uint
Digits uint Digits uint

View file

@ -1,18 +1,38 @@
package pwgen package pwgen
import (
"math/rand"
"time"
)
var ( var (
_ Generator = (*DefaultGenerator)(nil) _ Generator = (*DefaultGenerator)(nil)
Default DefaultGenerator Default = NewDefaultGenerator(nil)
lowerCase = alphabet('a', 'z') lowerCase = alphabet('a', 'z')
upperCase = alphabet('A', 'Z') upperCase = alphabet('A', 'Z')
letters = merge(lowerCase, upperCase) letters = merge(lowerCase, upperCase)
digits = alphabet('0', '9') digits = alphabet('0', '9')
) )
type DefaultGenerator struct { func Generate(opts ...GenerationOption) (string, error) {
return Default.Generate(opts...)
} }
func (d DefaultGenerator) Generate(opts ...GeneratorOption) (string, error) { func NewDefaultGenerator(prng Int32n) DefaultGenerator {
if prng == nil {
prng = rand.New(rand.NewSource(time.Now().UnixNano()))
}
return DefaultGenerator{
PRNG: prng,
}
}
type DefaultGenerator struct {
PRNG Int32n
}
func (d DefaultGenerator) Generate(opts ...GenerationOption) (string, error) {
compiledOptions := defaultOptions(opts...) compiledOptions := defaultOptions(opts...)
fullAlphabet := merge(lowerCase, upperCase, digits, []rune(compiledOptions.SpecialsAlphabet)) fullAlphabet := merge(lowerCase, upperCase, digits, []rune(compiledOptions.SpecialsAlphabet))
@ -24,28 +44,28 @@ func (d DefaultGenerator) Generate(opts ...GeneratorOption) (string, error) {
generated := make([]rune, 0, effectiveLength) generated := make([]rune, 0, effectiveLength)
for i := uint(0); i < compiledOptions.Lowercase; i++ { for i := uint(0); i < compiledOptions.Lowercase; i++ {
generated = append(generated, runeFor(lowerCase, compiledOptions.PRNG)) generated = append(generated, runeFor(lowerCase, d.PRNG))
} }
for i := uint(0); i < compiledOptions.Uppercase; i++ { for i := uint(0); i < compiledOptions.Uppercase; i++ {
generated = append(generated, runeFor(upperCase, compiledOptions.PRNG)) generated = append(generated, runeFor(upperCase, d.PRNG))
} }
for i := uint(0); i < compiledOptions.Digits; i++ { for i := uint(0); i < compiledOptions.Digits; i++ {
generated = append(generated, runeFor(digits, compiledOptions.PRNG)) generated = append(generated, runeFor(digits, d.PRNG))
} }
for i := uint(0); i < compiledOptions.Specials; i++ { for i := uint(0); i < compiledOptions.Specials; i++ {
generated = append(generated, runeFor([]rune(compiledOptions.SpecialsAlphabet), compiledOptions.PRNG)) generated = append(generated, runeFor([]rune(compiledOptions.SpecialsAlphabet), d.PRNG))
} }
for i := compiledOptions.Lowercase + compiledOptions.Uppercase; i < compiledOptions.Letters; i++ { for i := compiledOptions.Lowercase + compiledOptions.Uppercase; i < compiledOptions.Letters; i++ {
generated = append(generated, runeFor(letters, compiledOptions.PRNG)) generated = append(generated, runeFor(letters, d.PRNG))
} }
for i := uint(len(generated)); i < effectiveLength; i++ { for i := uint(len(generated)); i < effectiveLength; i++ {
generated = append(generated, runeFor(fullAlphabet, compiledOptions.PRNG)) generated = append(generated, runeFor(fullAlphabet, d.PRNG))
} }
return string(shuffle(generated, compiledOptions.PRNG)), nil return string(shuffle(generated, d.PRNG)), nil
} }