// Package options provides a way to initialise options package options import ( "log" "sync" ) // Options is used for initialisation type Options interface { // Initialise options Init(...Option) error // Options returns the current options Values() *Values // The name for who these options exist String() string } // Values holds the set of option values and protects them type Values struct { sync.RWMutex values map[interface{}]interface{} } // Option gives access to options type Option func(o *Values) error // Get a value from options func (o *Values) Get(k interface{}) (interface{}, bool) { o.RLock() defer o.RUnlock() v, ok := o.values[k] return v, ok } // Set a value in the options func (o *Values) Set(k, v interface{}) error { o.Lock() defer o.Unlock() if o.values == nil { o.values = map[interface{}]interface{}{} } o.values[k] = v return nil } // SetOption executes an option func (o *Values) Option(op Option) error { return op(o) } // WithValue allows you to set any value within the options func WithValue(k, v interface{}) Option { return func(o *Values) error { return o.Set(k, v) } } // WithOption gives you the ability to create an option that accesses values func WithOption(o Option) Option { return o } // String sets the string func WithString(s string) Option { return WithValue(stringKey{}, s) } // NewOptions returns a new initialiser func NewOptions(opts ...Option) Options { o := new(defaultOptions) if err := o.Init(opts...); err != nil { log.Fatal(err) } return o }