diff --git a/cache.go b/cache.go index 065b8d6..9107e0a 100644 --- a/cache.go +++ b/cache.go @@ -12,6 +12,8 @@ import ( "sync" ) +const defaultCacheTag = "schema" + var errInvalidPath = errors.New("schema: invalid path") // newCache returns a new cache. @@ -19,7 +21,7 @@ func newCache() *cache { c := cache{ m: make(map[reflect.Type]*structInfo), regconv: make(map[reflect.Type]Converter), - tag: "schema", + tag: defaultCacheTag, } return &c } diff --git a/decoder.go b/decoder.go index 54c88ec..44a30e0 100644 --- a/decoder.go +++ b/decoder.go @@ -16,9 +16,43 @@ const ( defaultMaxSize = 16000 ) +type option[T Decoder | Encoder] func(d *T) + // NewDecoder returns a new Decoder. -func NewDecoder() *Decoder { - return &Decoder{cache: newCache(), maxSize: defaultMaxSize} +func NewDecoder(opts ...option[Decoder]) *Decoder { + d := &Decoder{cache: newCache(), maxSize: defaultMaxSize} + for _, opt := range opts { + opt(d) + } + return d +} + +// See [Decoder.SetAliasTag] for more information. +func WithAliasTagDecoderOpt(tag string) option[Decoder] { + return func(d *Decoder) { + d.SetAliasTag(tag) + } +} + +// See [Decoder.ZeroEmpty] for more information. +func WithZeroEmptyDecoderOpt(z bool) option[Decoder] { + return func(d *Decoder) { + d.ZeroEmpty(z) + } +} + +// See [Decoder.IgnoreUnknownKeys] for more information. +func WithIgnoreUnknownKeysDecoderOpt(i bool) option[Decoder] { + return func(d *Decoder) { + d.IgnoreUnknownKeys(i) + } +} + +// See [Decoder.MaxSize] for more information. +func WithMaxSizeDecoderOpt(size int) option[Decoder] { + return func(d *Decoder) { + d.MaxSize(size) + } } // Decoder decodes values from a map[string][]string to a struct. diff --git a/decoder_test.go b/decoder_test.go index d01569e..cf59749 100644 --- a/decoder_test.go +++ b/decoder_test.go @@ -2527,3 +2527,47 @@ func TestDecoder_SetMaxSize(t *testing.T) { } }) } + +func TestNewDecoderWithOptions(t *testing.T) { + defaultDecoder := NewDecoder() + + aliasTag := defaultDecoder.cache.tag + "-test" + decoder := NewDecoder( + WithAliasTagDecoderOpt(aliasTag), + WithZeroEmptyDecoderOpt(!defaultDecoder.zeroEmpty), + WithIgnoreUnknownKeysDecoderOpt(!defaultDecoder.ignoreUnknownKeys), + WithMaxSizeDecoderOpt(defaultDecoder.maxSize+1), + ) + + if decoder.cache.tag != aliasTag { + t.Errorf( + "Expected Decoder.cache.tag to be %q, got %q", + aliasTag, + decoder.cache.tag, + ) + } + + if decoder.ignoreUnknownKeys == defaultDecoder.ignoreUnknownKeys { + t.Errorf( + "Expected Decoder.ignoreUnknownKeys to be %t, got %t", + !decoder.ignoreUnknownKeys, + decoder.ignoreUnknownKeys, + ) + } + + if decoder.zeroEmpty == defaultDecoder.zeroEmpty { + t.Errorf( + "Expected Decoder.zeroEmpty to be %t, got %t", + !decoder.zeroEmpty, + decoder.zeroEmpty, + ) + } + + if decoder.maxSize != defaultDecoder.maxSize+1 { + t.Errorf( + "Expected Decoder.maxSize to be %d, got %d", + defaultDecoder.maxSize+1, + decoder.maxSize, + ) + } +} diff --git a/encoder.go b/encoder.go index 52f2c10..215f511 100644 --- a/encoder.go +++ b/encoder.go @@ -16,8 +16,19 @@ type Encoder struct { } // NewEncoder returns a new Encoder with defaults. -func NewEncoder() *Encoder { - return &Encoder{cache: newCache(), regenc: make(map[reflect.Type]encoderFunc)} +func NewEncoder(opts ...option[Encoder]) *Encoder { + e := &Encoder{cache: newCache(), regenc: make(map[reflect.Type]encoderFunc)} + for _, opt := range opts { + opt(e) + } + return e +} + +// See [Encoder.SetAliasTag] for more information. +func WithAliasTagEncoderOpt(tag string) option[Encoder] { + return func(e *Encoder) { + e.SetAliasTag(tag) + } } // Encode encodes a struct into map[string][]string. diff --git a/encoder_test.go b/encoder_test.go index 092f0de..654df35 100644 --- a/encoder_test.go +++ b/encoder_test.go @@ -523,3 +523,18 @@ func TestRegisterEncoderWithPtrType(t *testing.T) { valExists(t, "DateStart", ss.DateStart.time.String(), vals) valExists(t, "DateEnd", "", vals) } + +func TestNewEncoderWithOptions(t *testing.T) { + aliasTag := defaultCacheTag + "-test" + encoder := NewEncoder( + WithAliasTagEncoderOpt(aliasTag), + ) + + if encoder.cache.tag != aliasTag { + t.Errorf( + "Expected Encoder.cache.tag to be %q, got %q", + aliasTag, + encoder.cache.tag, + ) + } +}