Package govalue
import "github.com/ornew/hff/adapters/govalue"
Generated from this checkout's Go source. Released versions are also on pkg.go.dev.
Overview
Package govalue adapts Go records to HFF while keeping reflection out of the compiler and backend contracts.
Choose NewBinding[T] when the Go type is the input contract. It infers the HFF schema once and provides Binding.Build and Filter.Match for typed Go records. Struct names prefer hff tags, then json tags, then exported Go field names; omitempty permits missing fields. Recursive Go types and ambiguous promoted field names are rejected during construction.
Binding object roots are nonnullable: a pointer to a struct or a string-keyed map can configure an engine, but a nil root record is rejected as invalid input. Nested nil pointers, maps, and slices become explicit HFF nulls. Other root types can be inferred for conversion-only use without an engine.
Choose New with WithSchema and WithStructs when an externally defined HFF schema should stay independent of Go structs. Explicit StructMapping maps HFF keys to direct exported Go field names; tags and embedded promotion are not inferred by this converter. String-keyed maps need no struct mapping.
Conversion preserves numeric kinds and distinguishes missing keys from null. It creates owned immutable HFF values, validates the resulting schema, and returns typed errors without partial output. Keep source records unchanged during conversion or matching; a shared Binding or Converter may otherwise be used concurrently. There is no conversion back into mutable Go records.
Index
Types
type Binding
type Binding[T any] struct {
// contains filtered or unexported fields
}
Binding derives an immutable HFF schema and conversion plan from static Go type T. It can build typed local filters for repeated matching. Source values must not be mutated during conversion or evaluation.
func NewBinding
func NewBinding[T any](options ...Option) (*Binding[T], error)
NewBinding derives a schema from static Go type T. Engine use requires an object root (struct or string-keyed map). Pointers to object roots and map roots are inferred as nonnullable objects, so a nil object root is an InputError. Other root types can be used for conversion without an engine and retain their inferred nullability. Nil nested pointers, maps, and slices remain explicit nulls. Struct field names use an hff tag, then a json tag, then the Go name; omitempty makes a field optional and '-' skips it. Anonymous structs are promoted, and ambiguous promoted names, recursive types, unsupported fields, and unrecognized tag options are ConfigurationErrors. Options may set input limits; explicit schema and struct-mapping options are not accepted.
Example
{
type Record struct {
Name string `json:"name"`
Age int `json:"age"`
}
binding, err := govalue.NewBinding[*Record]()
if err != nil {
panic(err)
}
e, err := engine.New(
engine.WithSchema(binding.Schema()),
engine.WithCapabilities(capabilities.Standard()),
)
if err != nil {
panic(err)
}
ctx := context.Background()
program, err := e.Compile(ctx, `name age>=18`)
if err != nil {
panic(err)
}
filter, err := binding.Build(ctx, program)
if err != nil {
panic(err)
}
for _, record := range []*Record{{Name: "Alice", Age: 25}, {Name: "Bob", Age: 16}} {
matched, err := filter.Match(ctx, record)
if err != nil {
panic(err)
}
if matched {
fmt.Println(record.Name)
}
}
}
Complete runnable example
package main
import (
"context"
"fmt"
"github.com/ornew/hff/adapters/govalue"
"github.com/ornew/hff/capabilities"
"github.com/ornew/hff/engine"
)
func main() {
type Record struct {
Name string `json:"name"`
Age int `json:"age"`
}
binding, err := govalue.NewBinding[*Record]()
if err != nil {
panic(err)
}
e, err := engine.New(
engine.WithSchema(binding.Schema()),
engine.WithCapabilities(capabilities.Standard()),
)
if err != nil {
panic(err)
}
ctx := context.Background()
program, err := e.Compile(ctx, `name age>=18`)
if err != nil {
panic(err)
}
filter, err := binding.Build(ctx, program)
if err != nil {
panic(err)
}
for _, record := range []*Record{{Name: "Alice", Age: 25}, {Name: "Bob", Age: 16}} {
matched, err := filter.Match(ctx, record)
if err != nil {
panic(err)
}
if matched {
fmt.Println(record.Name)
}
}
}
Output:
Alice
func (*Binding[T]) Build
func (b *Binding[T]) Build(ctx context.Context, program hff.Program, options ...local.Option) (*Filter[T], error)
Build constructs a typed local filter only when program carries the exact inferred schema. The Program must still have an engine-compatible object root. Options configure local evaluation; local Build errors are returned.
func (*Binding[T]) Convert
func (b *Binding[T]) Convert(ctx context.Context, source T) (hff.Value, error)
Convert maps source to an immutable HFF Value and checks the inferred schema. It returns no partial value on cancellation, input-limit, or validation errors. Keep source unchanged for the duration of the call.
func (*Binding[T]) Schema
func (b *Binding[T]) Schema() hff.Type
Schema returns the immutable inferred HFF schema, or an invalid Type for a nil Binding.
type Config
type Config struct {
// Schema is the required explicit HFF schema for New.
Schema hff.Type
// Structs maps concrete Go struct types to HFF object keys.
Structs []StructMapping
// MaxInputDepth and MaxInputValues bound both Go traversal (including
// pointer/interface wrappers) and subsequent HFF validation independently.
Limits hff.Limits
// UnlimitedLimits explicitly disables the adapter's input depth/value limits.
UnlimitedLimits bool
}
Config describes an explicit Go-to-HFF conversion. Schema is required; Structs maps Go structs to HFF object fields. Only input depth/value limits are used, both while traversing Go wrappers and while validating the HFF result. Other Limits fields do not impose conversion budgets.
type Converter
type Converter struct {
// contains filtered or unexported fields
}
Converter owns a snapshot of its configuration and supports concurrent calls. Source records must not be mutated while Convert is running.
func New
func New(options ...Option) (*Converter, error)
New applies options from left to right, validates and snapshots the result, and requires an explicit valid schema. Zero limits select finite input defaults. The returned Converter supports concurrent calls as long as each source value remains unchanged during conversion.
Example
{
type Person struct {
DisplayName string
Years int
}
converter, err := govalue.New(
govalue.WithSchema(schema.Struct(schema.String("name"), schema.Int("age"))),
govalue.WithStructs(govalue.StructMapping{
Type: reflect.TypeFor[Person](),
Fields: map[string]string{"name": "DisplayName", "age": "Years"},
}),
)
if err != nil {
panic(err)
}
value, err := converter.Convert(context.Background(), Person{DisplayName: "Alice", Years: 25})
if err != nil {
panic(err)
}
name, _ := value.Lookup("name")
text, _ := name.AsString()
fmt.Println(text)
}
Complete runnable example
package main
import (
"context"
"fmt"
"reflect"
"github.com/ornew/hff/adapters/govalue"
"github.com/ornew/hff/schema"
)
func main() {
type Person struct {
DisplayName string
Years int
}
converter, err := govalue.New(
govalue.WithSchema(schema.Struct(schema.String("name"), schema.Int("age"))),
govalue.WithStructs(govalue.StructMapping{
Type: reflect.TypeFor[Person](),
Fields: map[string]string{"name": "DisplayName", "age": "Years"},
}),
)
if err != nil {
panic(err)
}
value, err := converter.Convert(context.Background(), Person{DisplayName: "Alice", Years: 25})
if err != nil {
panic(err)
}
name, _ := value.Lookup("name")
text, _ := name.AsString()
fmt.Println(text)
}
Output:
Alice
func (*Converter) Convert
func (c *Converter) Convert(ctx context.Context, source any) (hff.Value, error)
Convert maps one Go value to an HFF Value and validates it against the Converter's explicit schema. It preserves numeric representations without coercion and does not infer names from tags. Nil pointers, maps, slices, interfaces, and nil itself become explicit null; non-nil empty containers remain empty. Cycles, unsupported representations, invalid text, cancellation, exceeded input limits, and schema mismatches return typed errors without a partial Value. Do not mutate source while conversion is running.
Example
{
converter, err := govalue.New(govalue.WithSchema(schema.Struct(schema.Int("age"))))
if err != nil {
panic(err)
}
value, err := converter.Convert(context.Background(), map[string]any{"age": int64(25)})
if err != nil {
panic(err)
}
age, _ := value.Lookup("age")
integer, ok := age.AsInt()
fmt.Println(integer, ok)
}
Complete runnable example
package main
import (
"context"
"fmt"
"github.com/ornew/hff/adapters/govalue"
"github.com/ornew/hff/schema"
)
func main() {
converter, err := govalue.New(govalue.WithSchema(schema.Struct(schema.Int("age"))))
if err != nil {
panic(err)
}
// A string-keyed Go map needs no StructMapping. Conversion preserves the
// integer kind instead of promoting it to a floating value.
value, err := converter.Convert(context.Background(), map[string]any{"age": int64(25)})
if err != nil {
panic(err)
}
age, _ := value.Lookup("age")
integer, ok := age.AsInt()
fmt.Println(integer, ok)
}
Output:
25 true
type Filter
type Filter[T any] struct {
// contains filtered or unexported fields
}
Filter evaluates a Program against Go values of T using its Binding's conversion plan. It is immutable and safe for concurrent calls when records are not mutated during matching.
func (*Filter[T]) Match
func (f *Filter[T]) Match(ctx context.Context, record T) (bool, error)
Match converts and validates record before evaluating the local filter. A completed false result is not an error; conversion, input, cancellation, and evaluation-limit failures are returned as typed errors.
type Option
type Option struct {
// contains filtered or unexported fields
}
Option changes one Converter setting. New applies options from left to right.
func WithConfig
func WithConfig(config *Config) Option
WithConfig copies a complete Converter configuration. Nil is rejected, and later options replace fields copied from this value.
func WithLimits
func WithLimits(limits hff.Limits) Option
WithLimits selects input traversal/validation limits. Other limit fields are validated but do not control conversion; zero input limits resolve to finite defaults.
func WithSchema
func WithSchema(schema hff.Type) Option
WithSchema sets the required explicit HFF root schema for New.
func WithStructs
func WithStructs(mappings ...StructMapping) Option
WithStructs sets explicit Go struct mappings. New copies the slice and maps.
func WithUnlimitedLimits
func WithUnlimitedLimits() Option
WithUnlimitedLimits disables this adapter's input depth/value limits.
type StructMapping
type StructMapping struct {
// Type is the exact Go struct type to map, typically reflect.TypeFor[T]().
Type reflect.Type
// Fields maps HFF field names to Go field names.
Fields map[string]string
}
StructMapping explicitly maps an HFF object type to one Go struct type. Fields maps HFF object keys to direct exported Go field names; embedded or promoted fields are not accepted by this explicit mapping. Unmapped Go fields are omitted from the converted object.