1
0
bind/lib.go

149 lines
4.5 KiB
Go
Raw Normal View History

2025-08-31 17:11:09 +02:00
// Package bind provides functions to work with flattened lists of structure fields.
2025-08-27 21:03:25 +02:00
package bind
2025-08-31 17:11:09 +02:00
// Scalar defines scalar types that can be used as field values and are not traversed.
2025-08-31 02:56:26 +02:00
type Scalar int
const (
Any Scalar = iota
Bool
Int
Uint
Float
String
2025-08-31 17:11:09 +02:00
Duration
Time
2025-08-31 02:56:26 +02:00
)
2025-08-31 17:11:09 +02:00
// 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.
2025-08-27 21:03:25 +02:00
type Field struct {
2025-08-31 17:11:09 +02:00
input bool
2025-08-31 02:56:26 +02:00
path []string
name string
list bool
typ Scalar
size int
free bool
value any
2025-08-27 21:03:25 +02:00
}
2025-08-31 17:11:09 +02:00
// 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.
2025-08-27 21:03:25 +02:00
func BindScalar(receiver any, value ...any) bool {
return bindScalarReflect(receiver, value)
}
2025-08-31 17:11:09 +02:00
// BindScalarCreate is like BindScalar, but it allocates the receiver from the type T.
2025-08-27 21:03:25 +02:00
func BindScalarCreate[T any](value ...any) (T, bool) {
return bindScalarCreateReflect[T](value)
}
2025-08-31 17:11:09 +02:00
// ValueByPath defines a field for input to BindFields or BindFieldsCreate. It defines the field by its exact
// field path in the receiver structure.
2025-08-31 00:40:47 +02:00
func ValueByPath(path []string, value any) Field {
2025-08-31 17:11:09 +02:00
return Field{input: true, path: path, value: value}
2025-08-27 21:03:25 +02:00
}
2025-08-31 17:11:09 +02:00
// 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.
2025-08-31 00:40:47 +02:00
func NamedValue(name string, value any) Field {
2025-08-31 17:11:09 +02:00
return Field{input: true, name: name, value: value}
2025-08-27 21:03:25 +02:00
}
2025-08-31 17:11:09 +02:00
// Path returns the structure path of a field.
2025-08-27 21:03:25 +02:00
func (f Field) Path() []string {
p := make([]string, len(f.path))
copy(p, f.path)
return p
}
2025-08-31 17:11:09 +02:00
// Name returns the structure path of a field concatenated and in kebab casing, unless defined otherwise by
// NamedValue.
2025-08-31 00:40:47 +02:00
func (f Field) Name() string {
if f.name != "" || len(f.path) == 0 {
return f.name
}
return nameFromPath(f.path)
}
2025-08-31 17:11:09 +02:00
// List indicates whether a field is wrapped in a slice and accpets multiple values.
func (f Field) List() bool { return f.list }
2025-08-27 21:03:25 +02:00
2025-08-31 17:11:09 +02:00
// 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.
2025-08-27 21:03:25 +02:00
func Fields[T any]() []Field {
2025-08-28 05:04:06 +02:00
return fieldsReflect[T]()
2025-08-27 21:03:25 +02:00
}
2025-08-31 17:11:09 +02:00
// FieldValues returns the fields of a structure value recursively. It traverses through pointers, slices and
// interfaces.
2025-08-27 21:03:25 +02:00
func FieldValues(structure any) []Field {
2025-08-28 05:04:06 +02:00
return fieldValuesReflect(structure)
2025-08-27 21:03:25 +02:00
}
2025-08-31 17:11:09 +02:00
// 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.
2025-08-31 00:40:47 +02:00
func BindFields(structure any, values ...Field) []Field {
return bindFieldsReflect(structure, values)
2025-08-27 21:03:25 +02:00
}
2025-08-31 17:11:09 +02:00
// BindFieldsCreate is like BindFields, but it allocates the receiver from type T.
2025-08-31 00:40:47 +02:00
func BindFieldsCreate[T any](values ...Field) (T, []Field) {
2025-08-31 01:49:53 +02:00
return bindFieldsCreateReflect[T](values)
2025-08-27 21:03:25 +02:00
}
2025-08-31 17:11:09 +02:00
// AcceptsScalar checks if a type can be used with BindScalarCreate or the values of the type with BindScalar.
2025-08-27 21:03:25 +02:00
func AcceptsScalar[T any]() bool {
return acceptsScalarReflect[T]()
}
2025-08-31 17:11:09 +02:00
// AcceptsFields checks if a type can be used with BindFieldsCreate or the values of the type with BindFields.
2025-08-27 21:03:25 +02:00
func AcceptsFields[T any]() bool {
return acceptsFieldsReflect[T]()
}
2025-08-31 17:11:09 +02:00
// AcceptsList checks if a type can be used to bind multiple values.
2025-08-27 21:03:25 +02:00
func AcceptsList[T any]() bool {
return acceptsListReflect[T]()
}
2025-08-31 17:11:09 +02:00
// Bindable is the same as AcceptsScalar[T]() || AcceptsFields[T]().
2025-08-27 21:03:25 +02:00
func Bindable[T any]() bool {
return bindableReflect[T]()
}