Skip to content

Commit

Permalink
Added a generator constructor that accepts options (#111)
Browse files Browse the repository at this point in the history
* feat: add generator with options

* fix: do not apply a nil option

* fix: nil safe for  generator's options

* docs: enhance doc

* fix: 100% coverage

* fix: nil constructors

* fix: with dummy generator

* nil test

* chore: add basic test to increase coverage

* fix identation

Co-authored-by: Cameron Ackerman <cameron_ackerman@selinc.com>
  • Loading branch information
LeonanCarvalho and cameracker committed Jan 23, 2023
1 parent 6ba114c commit f1cfba7
Show file tree
Hide file tree
Showing 2 changed files with 275 additions and 4 deletions.
76 changes: 72 additions & 4 deletions generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ import (
// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
const epochStart = 122192928000000000

type epochFunc func() time.Time
// EpochFunc is the function type used to provide the current time.
type EpochFunc func() time.Time

// HWAddrFunc is the function type used to provide hardware (MAC) addresses.
type HWAddrFunc func() (net.HardwareAddr, error)
Expand Down Expand Up @@ -119,13 +120,16 @@ type Gen struct {

rand io.Reader

epochFunc epochFunc
epochFunc EpochFunc
hwAddrFunc HWAddrFunc
lastTime uint64
clockSequence uint16
hardwareAddr [6]byte
}

// GenOption is a function type that can be used to configure a Gen generator.
type GenOption func(*Gen)

// interface check -- build will fail if *Gen doesn't satisfy Generator
var _ Generator = (*Gen)(nil)

Expand All @@ -147,11 +151,75 @@ func NewGen() *Gen {
// MAC address being used, you'll need to create a new generator using this
// function.
func NewGenWithHWAF(hwaf HWAddrFunc) *Gen {
return &Gen{
return NewGenWithOptions(WithHWAddrFunc(hwaf))
}

// NewGenWithOptions returns a new instance of Gen with the options provided.
// Most people should use NewGen() or NewGenWithHWAF() instead.
//
// To customize the generator, you can pass in one or more GenOption functions.
// For example:
//
// gen := NewGenWithOptions(
// WithHWAddrFunc(myHWAddrFunc),
// WithEpochFunc(myEpochFunc),
// WithRandomReader(myRandomReader),
// )
//
// NewGenWithOptions(WithHWAddrFunc(myHWAddrFunc)) is equivalent to calling
// NewGenWithHWAF(myHWAddrFunc)
// NewGenWithOptions() is equivalent to calling NewGen()
func NewGenWithOptions(opts ...GenOption) *Gen {
gen := &Gen{
epochFunc: time.Now,
hwAddrFunc: hwaf,
hwAddrFunc: defaultHWAddrFunc,
rand: rand.Reader,
}

for _, opt := range opts {
opt(gen)
}

return gen
}

// WithHWAddrFunc is a GenOption that allows you to provide your own HWAddrFunc
// function.
// When this option is nil, the defaultHWAddrFunc is used.
func WithHWAddrFunc(hwaf HWAddrFunc) GenOption {
return func(gen *Gen) {
if hwaf == nil {
hwaf = defaultHWAddrFunc
}

gen.hwAddrFunc = hwaf
}
}

// WithEpochFunc is a GenOption that allows you to provide your own EpochFunc
// function.
// When this option is nil, time.Now is used.
func WithEpochFunc(epochf EpochFunc) GenOption {
return func(gen *Gen) {
if epochf == nil {
epochf = time.Now
}

gen.epochFunc = epochf
}
}

// WithRandomReader is a GenOption that allows you to provide your own random
// reader.
// When this option is nil, the default rand.Reader is used.
func WithRandomReader(reader io.Reader) GenOption {
return func(gen *Gen) {
if reader == nil {
reader = rand.Reader
}

gen.rand = reader
}
}

// NewV1 returns a UUID based on the current timestamp and MAC address.
Expand Down

0 comments on commit f1cfba7

Please sign in to comment.