1
0

add Scalar type enumeration

This commit is contained in:
Arpad Ryszka 2025-08-31 02:56:26 +02:00
parent 5363818043
commit cfa9b6e6f7
5 changed files with 100 additions and 15 deletions

View File

@ -65,7 +65,8 @@ func fields(t reflect.Type) []Field {
if acceptsScalar(tfi.Type) { if acceptsScalar(tfi.Type) {
var fi Field var fi Field
ft := unpackType(tfi.Type, pointer|slice) ft := unpackType(tfi.Type, pointer|slice)
fi.isBool = ft.Kind() == reflect.Bool fi.typ = scalarType(ft.Kind())
fi.size = scalarSize(ft.Kind())
fi.list = acceptsList(tfi.Type) fi.list = acceptsList(tfi.Type)
fi.name = strcase.ToKebab(tfi.Name) fi.name = strcase.ToKebab(tfi.Name)
fi.path = []string{tfi.Name} fi.path = []string{tfi.Name}
@ -104,7 +105,8 @@ func fields(t reflect.Type) []Field {
func fieldFromValue(v reflect.Value) Field { func fieldFromValue(v reflect.Value) Field {
var fi Field var fi Field
fi.value = v.Interface() fi.value = v.Interface()
fi.isBool = v.Kind() == reflect.Bool fi.typ = scalarType(v.Kind())
fi.size = valueSize(v)
return fi return fi
} }

View File

@ -60,7 +60,7 @@ func TestField(t *testing.T) {
} }
que := m["que"] que := m["que"]
if !slices.Equal(que.Path(), []string{"Que"}) || !que.Bool() { if !slices.Equal(que.Path(), []string{"Que"}) || que.Type() != bind.Bool {
t.Fatal(que.Name()) t.Fatal(que.Name())
} }
@ -184,8 +184,8 @@ func TestField(t *testing.T) {
v := s{Foo: 42, Bar: true} v := s{Foo: 42, Bar: true}
f := bind.FieldValues(v) f := bind.FieldValues(v)
if len(f) != 2 || if len(f) != 2 ||
f[0].Name() != "foo" || !slices.Equal(f[0].Path(), []string{"Foo"}) || f[0].Value() != 42 || f[0].Bool() || f[0].Name() != "foo" || !slices.Equal(f[0].Path(), []string{"Foo"}) || f[0].Value() != 42 || f[0].Type() == bind.Bool ||
f[1].Name() != "bar" || !slices.Equal(f[1].Path(), []string{"Bar"}) || f[1].Value() != true || !f[1.].Bool() { f[1].Name() != "bar" || !slices.Equal(f[1].Path(), []string{"Bar"}) || f[1].Value() != true || f[1.].Type() != bind.Bool {
t.Fatal() t.Fatal()
} }
}) })

18
lib.go
View File

@ -2,13 +2,26 @@
// circular type structures not supported // circular type structures not supported
// it handles scalar fields // it handles scalar fields
// primary use cases by design are: command line options, environment variables, ini file fields, URL query parameters, HTTP form values // primary use cases by design are: command line options, environment variables, ini file fields, URL query parameters, HTTP form values
// traverses pointers, slices, wrapper interfaces
package bind package bind
type Scalar int
const (
Any Scalar = iota
Bool
Int
Uint
Float
String
)
type Field struct { type Field struct {
path []string path []string
name string name string
list bool list bool
isBool bool typ Scalar
size int
free bool free bool
value any value any
} }
@ -45,7 +58,8 @@ func (f Field) Name() string {
} }
func (f Field) List() bool { return f.list } func (f Field) List() bool { return f.list }
func (f Field) Bool() bool { return f.isBool } func (f Field) Type() Scalar { return f.typ }
func (f Field) Size() int { return f.size }
func (f Field) Free() bool { return f.free } func (f Field) Free() bool { return f.free }
func (f Field) Value() any { return f.value } func (f Field) Value() any { return f.value }

View File

@ -1 +1,7 @@
add the kind to the field type but with time and duration support. Simplified for ints, uints and floats, with bit size. Skipping the unused ones. With different name, e.g. ScalarType
track down the cases when reflect can panic track down the cases when reflect can panic
documentation:
- give a short description for every exported symbol
- start from collecting the docs from the test cases
- extrace the common doc items from the function doc items
doc/test/code triangle

63
type.go
View File

@ -20,6 +20,69 @@ func (f unpackFlag) has(v unpackFlag) bool {
return f&v > 0 return f&v > 0
} }
func scalarType(k reflect.Kind) Scalar {
switch k {
case reflect.Bool:
return Bool
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return Int
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return Uint
case reflect.Float32, reflect.Float64:
return Float
case reflect.String:
return String
default:
return Any
}
}
func scalarSize(k reflect.Kind) int {
switch k {
case reflect.Bool:
return 1
case reflect.Int:
return int(reflect.TypeFor[int]().Size()) * 8
case reflect.Int8:
return 8
case reflect.Int16:
return 16
case reflect.Int32:
return 32
case reflect.Int64:
return 64
case reflect.Uint:
return int(reflect.TypeFor[uint]().Size()) * 8
case reflect.Uint8:
return 8
case reflect.Uint16:
return 16
case reflect.Uint32:
return 32
case reflect.Uint64:
return 64
case reflect.Float32:
return 32
case reflect.Float64:
return 64
case reflect.String:
return -1
default:
return -1
}
}
func valueSize(v reflect.Value) int {
switch v.Kind() {
case reflect.String:
return v.Len() * 8
case reflect.Interface:
return valueSize(unpackValue(v, pointer|slice|iface|anytype))
default:
return scalarSize(v.Kind())
}
}
func setVisited[T comparable](visited map[T]bool, k T) map[T]bool { func setVisited[T comparable](visited map[T]bool, k T) map[T]bool {
s := make(map[T]bool) s := make(map[T]bool)
for v := range visited { for v := range visited {