package form import ( "github.com/pkg/errors" ) type Attrs map[string]any type FieldUnmarshaller interface { Unmarshal(v string) error } type ValidationFunc func(f *Field) error type Field struct { name string attrs map[string]any validators []ValidationFunc } func (f *Field) Name() string { return f.name } func (f *Field) Get(key string) (value any, exists bool) { value, exists = f.attrs[key] return } func (f *Field) Set(key string, value any) { f.attrs[key] = value } func (f *Field) Del(key string) { delete(f.attrs, key) } func (f *Field) Attrs() map[string]any { return f.attrs } func (f *Field) Validate() error { for _, fn := range f.validators { if err := fn(f); err != nil { return errors.WithStack(err) } } return nil } func NewField(name string, attrs Attrs, validators ...ValidationFunc) *Field { return &Field{ name: name, attrs: attrs, validators: validators, } } func FormFieldAttr[T any](f *Form, name string, attr string) (T, error) { field := f.Field(name) if field == nil { return *new(T), errors.WithStack(ErrFieldNotFound) } value, err := FieldAttr[T](field, attr) if err != nil { return *new(T), errors.WithStack(err) } return value, nil } func FieldAttr[T any](f *Field, name string) (T, error) { raw, ok := f.Get(name) if !ok { return *new(T), errors.WithStack(ErrMissingValue) } value, ok := raw.(T) if !ok { return *new(T), errors.WithStack(ErrUnexpectedValue) } return value, nil }