149 lines
4.5 KiB
Go
149 lines
4.5 KiB
Go
// Package bind provides functions to work with flattened lists of structure fields.
|
|
package bind
|
|
|
|
// Scalar defines scalar types that can be used as field values and are not traversed.
|
|
type Scalar int
|
|
|
|
const (
|
|
Any Scalar = iota
|
|
Bool
|
|
Int
|
|
Uint
|
|
Float
|
|
String
|
|
Duration
|
|
Time
|
|
)
|
|
|
|
// Field is a field of structure or a compatible map. It is used as the output of the inspection functions, and
|
|
// as the input of the binding functions.
|
|
type Field struct {
|
|
input bool
|
|
path []string
|
|
name string
|
|
list bool
|
|
typ Scalar
|
|
size int
|
|
free bool
|
|
value any
|
|
}
|
|
|
|
// BindScalar sets the receiver to the provided value or values. It traverses the receiver through wrappers like
|
|
// pointers, slices and interfaces. If the receiver contains a slice which is greater or equal length as the
|
|
// number of the provided values, N, it sets the first N slice items to the values. It returns true, if the
|
|
// values were set. It returns false, if the values were not set, e.g. due to incompatible types.
|
|
func BindScalar(receiver any, value ...any) bool {
|
|
return bindScalarReflect(receiver, value)
|
|
}
|
|
|
|
// BindScalarCreate is like BindScalar, but it allocates the receiver from the type T.
|
|
func BindScalarCreate[T any](value ...any) (T, bool) {
|
|
return bindScalarCreateReflect[T](value)
|
|
}
|
|
|
|
// ValueByPath defines a field for input to BindFields or BindFieldsCreate. It defines the field by its exact
|
|
// field path in the receiver structure.
|
|
func ValueByPath(path []string, value any) Field {
|
|
return Field{input: true, path: path, value: value}
|
|
}
|
|
|
|
// NamedValue defines a field for inptu to BindFields or BindFieldsCreate. The name is the kebab case
|
|
// representation of the field path. The struct boundaries in the field path are not represented in the name,
|
|
// which leads to potentially ambigous field references, depending on the receiver type structure and naming. In
|
|
// case of ambigous fields, the field that can match multiple structure fields, will be bound to each matched
|
|
// structure field.
|
|
func NamedValue(name string, value any) Field {
|
|
return Field{input: true, name: name, value: value}
|
|
}
|
|
|
|
// Path returns the structure path of a field.
|
|
func (f Field) Path() []string {
|
|
p := make([]string, len(f.path))
|
|
copy(p, f.path)
|
|
return p
|
|
}
|
|
|
|
// Name returns the structure path of a field concatenated and in kebab casing, unless defined otherwise by
|
|
// NamedValue.
|
|
func (f Field) Name() string {
|
|
if f.name != "" || len(f.path) == 0 {
|
|
return f.name
|
|
}
|
|
|
|
return nameFromPath(f.path)
|
|
}
|
|
|
|
// List indicates whether a field is wrapped in a slice and accpets multiple values.
|
|
func (f Field) List() bool { return f.list }
|
|
|
|
// Type returns the scalar type of the field.
|
|
func (f Field) Type() Scalar {
|
|
if !f.input {
|
|
return f.typ
|
|
}
|
|
|
|
return scalarTypeReflect(f.value)
|
|
}
|
|
|
|
// Size returns the bitsize of the field.
|
|
func (f Field) Size() int {
|
|
if !f.input {
|
|
return f.size
|
|
}
|
|
|
|
return valueSizeReflect(f.value)
|
|
}
|
|
|
|
// Free indicates that the field was found in a map.
|
|
func (f Field) Free() bool {
|
|
return f.free
|
|
}
|
|
|
|
// Value returns the value of a field.
|
|
func (f Field) Value() any {
|
|
return f.value
|
|
}
|
|
|
|
// Fields returns the fields of a structure type recursively. It traverses through pointers and slices.
|
|
func Fields[T any]() []Field {
|
|
return fieldsReflect[T]()
|
|
}
|
|
|
|
// FieldValues returns the fields of a structure value recursively. It traverses through pointers, slices and
|
|
// interfaces.
|
|
func FieldValues(structure any) []Field {
|
|
return fieldValuesReflect(structure)
|
|
}
|
|
|
|
// BindFields sets structure fields recursively. It traverses through poitners, slices and interfaces. It
|
|
// returns the values for which it is not possible to find a compatible matching field. It supports maps that
|
|
// have string keys and scalar values.
|
|
func BindFields(structure any, values ...Field) []Field {
|
|
return bindFieldsReflect(structure, values)
|
|
}
|
|
|
|
// BindFieldsCreate is like BindFields, but it allocates the receiver from type T.
|
|
func BindFieldsCreate[T any](values ...Field) (T, []Field) {
|
|
return bindFieldsCreateReflect[T](values)
|
|
}
|
|
|
|
// AcceptsScalar checks if a type can be used with BindScalarCreate or the values of the type with BindScalar.
|
|
func AcceptsScalar[T any]() bool {
|
|
return acceptsScalarReflect[T]()
|
|
}
|
|
|
|
// AcceptsFields checks if a type can be used with BindFieldsCreate or the values of the type with BindFields.
|
|
func AcceptsFields[T any]() bool {
|
|
return acceptsFieldsReflect[T]()
|
|
}
|
|
|
|
// AcceptsList checks if a type can be used to bind multiple values.
|
|
func AcceptsList[T any]() bool {
|
|
return acceptsListReflect[T]()
|
|
}
|
|
|
|
// Bindable is the same as AcceptsScalar[T]() || AcceptsFields[T]().
|
|
func Bindable[T any]() bool {
|
|
return bindableReflect[T]()
|
|
}
|