fix: ensure pointers can be detected as bools
This required adding a BoolMapperExt interface.
This commit is contained in:
@@ -123,9 +123,16 @@ type VarsContributor interface {
|
||||
//
|
||||
// This is used solely for formatting help.
|
||||
type BoolMapper interface {
|
||||
Mapper
|
||||
IsBool() bool
|
||||
}
|
||||
|
||||
// BoolMapperExt allows a Mapper to dynamically determine if a value is a boolean.
|
||||
type BoolMapperExt interface {
|
||||
Mapper
|
||||
IsBoolFromValue(v reflect.Value) bool
|
||||
}
|
||||
|
||||
// A MapperFunc is a single function that complies with the Mapper interface.
|
||||
type MapperFunc func(ctx *DecodeContext, target reflect.Value) error
|
||||
|
||||
@@ -186,6 +193,7 @@ func (r *Registry) ForType(typ reflect.Type) Mapper {
|
||||
// Check if the type implements MapperValue.
|
||||
for _, impl := range []reflect.Type{typ, reflect.PtrTo(typ)} {
|
||||
if impl.Implements(mapperValueType) {
|
||||
// FIXME: This should pass in the bool mapper.
|
||||
return &mapperValueAdapter{impl.Implements(boolMapperType)}
|
||||
}
|
||||
}
|
||||
@@ -275,7 +283,7 @@ func (r *Registry) RegisterDefaults() *Registry {
|
||||
RegisterName("existingfile", existingFileMapper(r)).
|
||||
RegisterName("existingdir", existingDirMapper(r)).
|
||||
RegisterName("counter", counterMapper()).
|
||||
RegisterKind(reflect.Ptr, ptrMapper(r))
|
||||
RegisterKind(reflect.Ptr, ptrMapper{r})
|
||||
}
|
||||
|
||||
type boolMapper struct{}
|
||||
@@ -676,10 +684,31 @@ func existingDirMapper(r *Registry) MapperFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func ptrMapper(r *Registry) MapperFunc {
|
||||
return func(ctx *DecodeContext, target reflect.Value) error {
|
||||
type ptrMapper struct {
|
||||
r *Registry
|
||||
}
|
||||
|
||||
var _ BoolMapperExt = (*ptrMapper)(nil)
|
||||
|
||||
// IsBoolFromValue implements BoolMapperExt
|
||||
func (p ptrMapper) IsBoolFromValue(target reflect.Value) bool {
|
||||
elem := reflect.New(target.Type().Elem()).Elem()
|
||||
nestedMapper := r.ForValue(elem)
|
||||
nestedMapper := p.r.ForValue(elem)
|
||||
if nestedMapper == nil {
|
||||
return false
|
||||
}
|
||||
if bm, ok := nestedMapper.(BoolMapper); ok && bm.IsBool() {
|
||||
return true
|
||||
}
|
||||
if bm, ok := nestedMapper.(BoolMapperExt); ok && bm.IsBoolFromValue(target) {
|
||||
return true
|
||||
}
|
||||
return target.Kind() == reflect.Ptr && target.Type().Elem().Kind() == reflect.Bool
|
||||
}
|
||||
|
||||
func (p ptrMapper) Decode(ctx *DecodeContext, target reflect.Value) error {
|
||||
elem := reflect.New(target.Type().Elem()).Elem()
|
||||
nestedMapper := p.r.ForValue(elem)
|
||||
if nestedMapper == nil {
|
||||
return fmt.Errorf("cannot find mapper for %v", target.Type().Elem().String())
|
||||
}
|
||||
@@ -690,7 +719,6 @@ func ptrMapper(r *Registry) MapperFunc {
|
||||
target.Set(elem.Addr())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func counterMapper() MapperFunc {
|
||||
return func(ctx *DecodeContext, target reflect.Value) error {
|
||||
|
||||
@@ -318,6 +318,9 @@ func (v *Value) IsMap() bool {
|
||||
|
||||
// IsBool returns true if the underlying value is a boolean.
|
||||
func (v *Value) IsBool() bool {
|
||||
if m, ok := v.Mapper.(BoolMapperExt); ok && m.IsBoolFromValue(v.Target) {
|
||||
return true
|
||||
}
|
||||
if m, ok := v.Mapper.(BoolMapper); ok && m.IsBool() {
|
||||
return true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user