Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions custom_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"reflect"
"time"

"github.com/m0rjc/goconfig/internal/builtintypes"
"github.com/m0rjc/goconfig/internal/customtypes"
"github.com/m0rjc/goconfig/internal/readpipeline"
)
Expand All @@ -19,7 +20,7 @@ type TypedHandler[T any] = readpipeline.TypedHandler[T]
type Transform[T, U any] = customtypes.Transform[T, U]

func RegisterCustomType[T any](handler TypedHandler[T]) {
readpipeline.RegisterType[T](handler)
builtintypes.RegisterType[T](handler)
}

func NewCustomType[T any](customParser FieldProcessor[T], customValidators ...Validator[T]) TypedHandler[T] {
Expand Down Expand Up @@ -72,25 +73,25 @@ func TransformCustomType[T, U any](baseHandler TypedHandler[T], transform Transf
}

func DefaultStringType[T ~string]() TypedHandler[T] {
pipeline := readpipeline.NewTypedStringHandler()
pipeline := builtintypes.NewTypedStringHandler()
return CastCustomType[string, T](pipeline)
}

func DefaultIntegerType[T ~int | ~int8 | ~int16 | ~int32 | ~int64]() TypedHandler[T] {
t := reflect.TypeOf(T(0))
return CastCustomType[int64, T](readpipeline.NewTypedIntHandler(t.Bits()))
return CastCustomType[int64, T](builtintypes.NewTypedIntHandler(t.Bits()))
}

func DefaultUnsignedIntegerType[T ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64]() TypedHandler[T] {
t := reflect.TypeOf(T(0))
return CastCustomType[uint64, T](readpipeline.NewTypedUintHandler(t.Bits()))
return CastCustomType[uint64, T](builtintypes.NewTypedUintHandler(t.Bits()))
}

func DefaultFloatIntegerType[T ~float32 | ~float64]() TypedHandler[T] {
t := reflect.TypeOf(T(0))
return CastCustomType[float64, T](readpipeline.NewTypedFloatHandler(t.Bits()))
return CastCustomType[float64, T](builtintypes.NewTypedFloatHandler(t.Bits()))
}

func DefaultDurationType() TypedHandler[time.Duration] {
return readpipeline.NewTypedDurationHandler()
return builtintypes.NewTypedDurationHandler()
}
24 changes: 24 additions & 0 deletions internal/builtintypes/boolean_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package builtintypes

import (
"reflect"
"strconv"

"github.com/m0rjc/goconfig/internal/readpipeline"
)

func NewBoolHandler(_ reflect.Type) readpipeline.TypedHandler[bool] {
return NewTypedBoolHandler()
}

// NewTypedBoolHandler returns a TypedHandler[bool] that uses standard bool parsing and validation.
func NewTypedBoolHandler() readpipeline.TypedHandler[bool] {
return &typeHandlerImpl[bool]{
Parser: func(rawValue string) (bool, error) {
return strconv.ParseBool(rawValue)
},
ValidationWrapper: func(tags reflect.StructTag, inputProcess readpipeline.FieldProcessor[bool]) (readpipeline.FieldProcessor[bool], error) {
return inputProcess, nil
},
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package readpipeline
package builtintypes

import (
"reflect"
"testing"

"github.com/m0rjc/goconfig/internal/readpipeline"
)

func TestBoolTypes(t *testing.T) {
Expand Down Expand Up @@ -49,7 +51,7 @@ func TestBoolTypes(t *testing.T) {
registry := NewTypeRegistry()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
proc, err := New(tt.fieldType, tt.tags, registry)
proc, err := readpipeline.New(tt.fieldType, tt.tags, registry)
if err != nil {
t.Fatalf("New() error = %v", err)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package readpipeline
package builtintypes

import "time"
import (
"time"

"github.com/m0rjc/goconfig/internal/readpipeline"
)

var durationTypeHandler = NewTypedDurationHandler()

// NewTypedDurationHandler returns a TypedHandler[time.Duration] that uses standard duration parsing and validation.
func NewTypedDurationHandler() TypedHandler[time.Duration] {
func NewTypedDurationHandler() readpipeline.TypedHandler[time.Duration] {
return &typeHandlerImpl[time.Duration]{
Parser: func(rawValue string) (time.Duration, error) {
return time.ParseDuration(rawValue)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package readpipeline
package builtintypes

import (
"reflect"
"testing"
"time"

"github.com/m0rjc/goconfig/internal/readpipeline"
)

func TestDurationTypes(t *testing.T) {
Expand Down Expand Up @@ -46,7 +48,7 @@ func TestDurationTypes(t *testing.T) {
registry := NewTypeRegistry()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
proc, err := New(tt.fieldType, tt.tags, registry)
proc, err := readpipeline.New(tt.fieldType, tt.tags, registry)
if err != nil {
t.Fatalf("New() error = %v", err)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package readpipeline
package builtintypes

import (
"encoding/json"
"fmt"
"reflect"

"github.com/m0rjc/goconfig/internal/readpipeline"
)

func NewJsonPipelineBuilder(targetType reflect.Type) TypedHandler[any] {
func NewJsonPipelineBuilder(targetType reflect.Type) readpipeline.TypedHandler[any] {
return &typeHandlerImpl[any]{
Parser: func(rawValue string) (any, error) {
ptr := reflect.New(targetType).Interface()
Expand All @@ -22,7 +24,7 @@ func NewJsonPipelineBuilder(targetType reflect.Type) TypedHandler[any] {
return reflect.ValueOf(ptr).Elem().Interface(), nil
},

ValidationWrapper: func(tags reflect.StructTag, inputProcess FieldProcessor[any]) (FieldProcessor[any], error) {
ValidationWrapper: func(tags reflect.StructTag, inputProcess readpipeline.FieldProcessor[any]) (readpipeline.FieldProcessor[any], error) {
return inputProcess, nil
},
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package readpipeline
package builtintypes

import (
"reflect"
"testing"

"github.com/m0rjc/goconfig/internal/readpipeline"
)

func TestJsonTypes(t *testing.T) {
Expand Down Expand Up @@ -42,7 +44,7 @@ func TestJsonTypes(t *testing.T) {
registry := NewTypeRegistry()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
proc, err := New(tt.fieldType, tt.tags, registry)
proc, err := readpipeline.New(tt.fieldType, tt.tags, registry)
if err != nil {
t.Fatalf("New() error = %v", err)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
package readpipeline
package builtintypes

import (
"reflect"
"strconv"

"github.com/m0rjc/goconfig/internal/readpipeline"
)

func NewIntHandler(fieldType reflect.Type) TypedHandler[int64] {
func NewIntHandler(fieldType reflect.Type) readpipeline.TypedHandler[int64] {
return NewTypedIntHandler(fieldType.Bits())
}

func NewUintHandler(fieldType reflect.Type) TypedHandler[uint64] {
func NewUintHandler(fieldType reflect.Type) readpipeline.TypedHandler[uint64] {
return NewTypedUintHandler(fieldType.Bits())
}

func NewFloatHandler(fieldType reflect.Type) TypedHandler[float64] {
func NewFloatHandler(fieldType reflect.Type) readpipeline.TypedHandler[float64] {
return NewTypedFloatHandler(fieldType.Bits())
}

// NewTypedIntHandler returns a TypedHandler[int64] that uses standard int parsing and validation.
func NewTypedIntHandler(bits int) TypedHandler[int64] {
func NewTypedIntHandler(bits int) readpipeline.TypedHandler[int64] {
return &typeHandlerImpl[int64]{
Parser: func(rawValue string) (int64, error) {
return strconv.ParseInt(rawValue, 0, bits)
Expand All @@ -28,7 +30,7 @@ func NewTypedIntHandler(bits int) TypedHandler[int64] {
}

// NewTypedUintHandler returns a TypedHandler[uint64] that uses standard uint parsing and validation.
func NewTypedUintHandler(bits int) TypedHandler[uint64] {
func NewTypedUintHandler(bits int) readpipeline.TypedHandler[uint64] {
return &typeHandlerImpl[uint64]{
Parser: func(rawValue string) (uint64, error) {
return strconv.ParseUint(rawValue, 0, bits)
Expand All @@ -38,7 +40,7 @@ func NewTypedUintHandler(bits int) TypedHandler[uint64] {
}

// NewTypedFloatHandler returns a TypedHandler[float64] that uses standard float parsing and validation.
func NewTypedFloatHandler(bits int) TypedHandler[float64] {
func NewTypedFloatHandler(bits int) readpipeline.TypedHandler[float64] {
return &typeHandlerImpl[float64]{
Parser: func(rawValue string) (float64, error) {
return strconv.ParseFloat(rawValue, bits)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package readpipeline
package builtintypes

import (
"reflect"
"testing"

"github.com/m0rjc/goconfig/internal/readpipeline"
)

func TestIntTypes(t *testing.T) {
Expand Down Expand Up @@ -111,15 +113,15 @@ func TestIntTypes(t *testing.T) {

registry := NewTypeRegistry()
t.Run("invalid min tag", func(t *testing.T) {
_, err := New(reflect.TypeOf(int(0)), `min:"foo"`, registry)
_, err := readpipeline.New(reflect.TypeOf(int(0)), `min:"foo"`, registry)
if err == nil {
t.Error("expected error for invalid min tag, got nil")
}
})

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
proc, err := New(tt.fieldType, tt.tags, registry)
proc, err := readpipeline.New(tt.fieldType, tt.tags, registry)
if err != nil {
t.Fatalf("New() error = %v", err)
}
Expand Down Expand Up @@ -217,7 +219,7 @@ func TestUintTypes(t *testing.T) {
registry := NewTypeRegistry()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
proc, err := New(tt.fieldType, tt.tags, registry)
proc, err := readpipeline.New(tt.fieldType, tt.tags, registry)
if err != nil {
t.Fatalf("New() error = %v", err)
}
Expand Down Expand Up @@ -267,7 +269,7 @@ func TestFloatTypes(t *testing.T) {
registry := NewTypeRegistry()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
proc, err := New(tt.fieldType, tt.tags, registry)
proc, err := readpipeline.New(tt.fieldType, tt.tags, registry)
if err != nil {
t.Fatalf("New() error = %v", err)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package readpipeline
package builtintypes

import (
"cmp"
"fmt"
"reflect"

"github.com/m0rjc/goconfig/internal/readpipeline"
)

// orderedValidator is a validator that checks a value is within a range. The value must be comparable.
Expand Down Expand Up @@ -37,7 +39,7 @@ func newRangeValidator[T cmp.Ordered](minimum, maximum T) orderedValidator[T] {
}

// WrapProcessUsingRangeTags applies the min and max tags to an ordered readpipeline.
func WrapProcessUsingRangeTags[T cmp.Ordered](tags reflect.StructTag, processor FieldProcessor[T]) (FieldProcessor[T], error) {
func WrapProcessUsingRangeTags[T cmp.Ordered](tags reflect.StructTag, processor readpipeline.FieldProcessor[T]) (readpipeline.FieldProcessor[T], error) {
minTag, hasMin := tags.Lookup("min")
maxTag, hasMax := tags.Lookup("max")

Expand All @@ -57,13 +59,13 @@ func WrapProcessUsingRangeTags[T cmp.Ordered](tags reflect.StructTag, processor
}

if hasMin && hasMax {
return Pipe(processor, Validator[T](newRangeValidator(minimum, maximum))), nil
return readpipeline.Pipe(processor, readpipeline.Validator[T](newRangeValidator(minimum, maximum))), nil
}
if hasMin {
return Pipe(processor, Validator[T](newMinValidator(minimum))), nil
return readpipeline.Pipe(processor, readpipeline.Validator[T](newMinValidator(minimum))), nil
}
if hasMax {
return Pipe(processor, Validator[T](newMaxValidator(maximum))), nil
return readpipeline.Pipe(processor, readpipeline.Validator[T](newMaxValidator(maximum))), nil
}
return processor, nil
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
package readpipeline
package builtintypes

import (
"fmt"
"reflect"
"regexp"

"github.com/m0rjc/goconfig/internal/readpipeline"
)

// WrapProcessUsingPatternTag applies the pattern tag validation if present.
func WrapProcessUsingPatternTag(tags reflect.StructTag, processor FieldProcessor[string]) (FieldProcessor[string], error) {
func WrapProcessUsingPatternTag(tags reflect.StructTag, processor readpipeline.FieldProcessor[string]) (readpipeline.FieldProcessor[string], error) {
patternTag, hasPattern := tags.Lookup("pattern")

if hasPattern {
pattern, err := regexp.Compile(patternTag)
if err != nil {
return nil, err
}
return Pipe(processor, func(value string) error {
return readpipeline.Pipe(processor, func(value string) error {
if !pattern.MatchString(value) {
return fmt.Errorf("does not match pattern %s", patternTag)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package readpipeline
package builtintypes

import (
"reflect"
Expand Down
Loading
Loading