D3vugu-components/components/input/list-binder.go

113 lines
3.0 KiB
Go
Raw Permalink Normal View History

package input
import (
"fmt"
"strconv"
"golang.org/x/exp/slices"
)
// ListBinder describes an interface that simple lists can implement to be compatible with list based UI components.
type ListBinder interface {
ListKeyValuePairs() []ListKeyValuePair
ListDeleteKey(key string) bool // Removes the entry with the given key, and returns true if it got deleted successfully.
ListAddKeyValuePair(key, value string) error // Adds the key value pair to the list.
ListLen() int // Returns the length of the list.
}
type ListKeyValuePair struct {
Key, Value string
}
// ListBindGenericSlice implements ListBinder for slices that are of some arbitrary type.
//
// List keys will be bound to slice indices, and list values will be bound to a string representation of the slice elements.
type ListBindGenericSlice[T any] struct {
Slice *[]T
}
func (l ListBindGenericSlice[T]) ListKeyValuePairs() []ListKeyValuePair {
if l.Slice == nil {
return nil
}
result := make([]ListKeyValuePair, 0, len(*l.Slice))
for i, entry := range *l.Slice {
str := ValueBindAny{entry}.StringValue()
result = append(result, ListKeyValuePair{Key: strconv.Itoa(i), Value: str})
}
return result
}
func (l ListBindGenericSlice[T]) ListDeleteKey(key string) bool {
if l.Slice == nil {
return false
}
index, err := strconv.Atoi(key)
if err != nil {
return false
}
if index < 0 || index >= len(*l.Slice) {
return false
}
*l.Slice = slices.Delete(*l.Slice, index, index+1)
return true
}
func (l ListBindGenericSlice[T]) ListAddKeyValuePair(key, value string) error {
index, err := strconv.Atoi(key)
if err != nil {
return fmt.Errorf("failed to parse index: %w", err)
}
if index < 0 || index > len(*l.Slice) {
return fmt.Errorf("index %d out of bounds", index)
}
var val T
if err := (ValueBindAny{&val}).SetStringValue(value); err != nil {
return err
}
*l.Slice = slices.Insert(*l.Slice, index, val)
return nil
}
func (l ListBindGenericSlice[T]) ListLen() int {
return len(*l.Slice)
}
// ListBindGenericValues implements ListBinder for slices that are of some arbitrary type.
//
// List keys and values will be bound to the string representation of the slice elements.
//
// This is useful for dropdown components, as the key of the selected element will be set to the bound value.
//
// This can not modify the bound list.
type ListBindGenericValues[T any] []T
func (l ListBindGenericValues[T]) ListKeyValuePairs() []ListKeyValuePair {
result := make([]ListKeyValuePair, 0, len(l))
for _, entry := range l {
str := ValueBindAny{entry}.StringValue()
result = append(result, ListKeyValuePair{Key: str, Value: str})
}
return result
}
func (l ListBindGenericValues[T]) ListDeleteKey(key string) bool {
return false
}
func (l ListBindGenericValues[T]) ListAddKeyValuePair(key, value string) error {
return fmt.Errorf("the list binder doesn't support list modifications")
}
func (l ListBindGenericValues[T]) ListLen() int {
return len(l)
}