type_walk

package module
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 14, 2025 License: BSD-3-Clause Imports: 7 Imported by: 0

README

Go Reference

type-walk - Fast reflection for mere mortals

Warning: Experimental

type-walk is an experimental library. It probably has enough functionality to use in some real projects, but it still lacks features, and adding them over time may change the API. I've tried to test all possible edge cases and round off the sharp corners, but it's a big ball of unsafe code and it's possible I've missed some.

If you use this in production, do so at your own risk. Know that the benefits are critical to your project. Audit my code yourself, and test your own code rigorously. Be prepared to update your code in response to API changes or freeze the library to a specific version.

Quick Start

Installation
go get github.com/zolstein/type-walk
Basic Example
package main

import (
    "fmt"
    "strings"
    tw "github.com/zolstein/type-walk"
)

func main() {
    // Create a register and add a handler for strings
    register := tw.NewRegister[*strings.Builder]()

    tw.RegisterTypeFn(register, func(ctx *strings.Builder, v tw.String) error {
      ctx.WriteString(v.Get())
      return nil
    })

    // Create walker and use it
    walker := tw.NewWalker(register)
    var buf strings.Builder

    err := walker.Walk(&buf, "Hello, world!")
	if err != nil {
		panic(err)
    }
    fmt.Println(buf.String()) // Output: Hello, world!
}

Table of Contents

Why does this even exist?

The reflect package in Go is useful for writing general libraries that can process data of any type. However, it has a large drawback - it's SLOW. Many common patterns cause the runtime to allocate lots of memory. Allocating memory and collecting garbage are frequently large parts of Go programs' CPU time - in programs that use reflection, it is often a main contributor.

Some patterns can allow programmers to get the benefits of reflection while avoiding most of the runtime cost. One common pattern is to use reflection to analyze a type, "compile" a function that stores information about the type, and use this function to process many values of that type. However, this code needed to accomplish this can be gnarly. It can require converting every value to an unsafe.Pointer and using pointer-arithmetic to walk the type. Writing this is tedious, error-prone, and wildly unsafe.

type-walk attempts to abstract the unsafe code and provide a safe interface to build fast reflective code.

Examples

For complete, runnable examples see the package documentation or check out examples_test.go in this repository.

Basic pattern:

package main
import (
	"time"
    tw "github.com/zolstein/type-walk"
)
type YourContext struct {
    // Any data you want to pass into your walk functions
}
func main() {
	// 1. Create register and add handlers
	register := tw.NewRegister[YourContext]()
	// Directly register WalkFn handlers for types you want to handle specially.
	var yourTimeHandler tw.WalkFn[YourContext, time.Time]
	tw.RegisterTypeFn[YourContext, time.Time](register, yourTimeHandler)
	// Register CompileFn handlers to handle unknown types by kind.
	var yourStringHandler tw.CompileFn[YourContext, string]
	tw.RegisterCompileStringFn(register, yourStringHandler)
	var yourStructHandler tw.CompileStructFn[YourContext]
	tw.RegisterCompileStructFn(register, yourStructHandler)
	// 2. Create walker
	walker := tw.NewWalker(register)
	// 3. Walk your data
	var yourData any
	err := walker.Walk(YourContext{}, yourData)
}

Performance

Benchmark results comparing type-walk to standard reflection implementing a simplified JSON serializer:

Implementation Iterations ns/op B/op allocs/op
reflect 10,000 111,963 28,920 2,409
type-walk 24,776 49,587 0 0

Run go test -bench=. to see benchmarks on your system.

How does it work

type-walk uses a two-stage approach similar to Go's regexp package: compile once, use many times. All values of the same type have identical structure, so we can analyze each type once and reuse that analysis.

The Two Stages:

  1. Compile - Analyze a type and generate a fast walk function for it (like regexp.Compile)
  2. Walk - Use that pre-compiled walk function on actual values

Just as regexp does expensive analysis once to compile a fast Regexp, then uses it to search many strings, type-walk does expensive analysis once to compile a fast walk function, then uses it to process many values.

Walking

Walking means calling a function to recursively process a value. The walker:

  1. Uses reflection once to determine the value's type
  2. Finds the appropriate walk function (either pre-registered or compiled on-demand).
    1. If a registered walk function exists for the value's type, use it.
    2. If a compile function exists for the value's kind - int, struct, slice, etc. - compile a new walk function and register it for future use.
    3. Otherwise, return an error.
  3. Calls that function with your value

Walk Function Signature:

type WalkFn[Ctx any, In any] func(Ctx, Arg[In]) error
  • In - The type being processed (e.g., string, Person)
  • Arg[In] - Wrapper providing Get() and Set() methods for the value
  • Ctx - An arbitrary type to pass data into the WalkFn, or to store and return results.
    • Ctx should not be confused with context.Context. However, you might include a context.Context inside your Ctx type if you need it.
Compiling

Compiling creates walk functions for types that haven't been seen before. You register compile functions by kind - not specific type.

Compile Function Signature:

type CompileFn[Ctx any, In any] func(reflect.Type) WalkFn[Ctx, In]

A compile function takes a reflect.Type and returns a walk function for that specific type. For example, if you register a CompileFn[Ctx, int], it will be used to generate functions for int, type UserID int, type Count int, etc.

Example:

RegisterCompileIntFn(register, func(typ reflect.Type) WalkFn[Ctx, int] {
    return func(ctx Ctx, i Arg[int]) error {
        fmt.Printf("Processing %s: %d\n", typ.Name(), i.Get())
        return nil
    }
})
Complex Kinds

For complex types like slices, arrays, structs, and pointers, type-walk provides specialized types that enable recursive walking.

Slice Function signatures:

type WalkSliceFn[Ctx any] func(Ctx, Slice[Ctx]) error
type CompileSliceFn[Ctx any] func(reflect.Type) WalkSliceFn[Ctx]

Slice[Ctx] represents a slice and provides methods to access its length, capacity, and nil status. Most importantly, you can get an element with Elem(i) and recursively walk it with the element's Walk method.

Example:

RegisterCompileSliceFn(register, func(typ reflect.Type) WalkSliceFn[Ctx] {
    return func(ctx Ctx, s Slice[Ctx]) error {
        for i := 0; i < s.Len(); i++ {
            s.Elem(i).Walk(ctx) // Walk each element
        }
        return nil
    }
})

All other complex types have similar patterns - they provide specialized helper types that let you examine some information about them, and recursively walk their contents.

Structs

Structs are more complex than slices because they can have fields of multiple different types. Additionally, you may not want to process all fields of every struct.

Function signature:

type CompileStructFn[Ctx any] func(reflect.Type, StructFieldRegister) WalkStructFn[Ctx]

You must use the StructFieldRegister in the CompileStructFn to explicitly register which fields you want to be available in the WalkStructFn.

Field registration methods:

  • RegisterField(fieldNum) - Register a direct field by number
  • RegisterFieldByIndex([]int{...}) - Register nested fields (like person.Address.Street)

Example:

RegisterCompileStructFn(register, func(typ reflect.Type, reg StructFieldRegister) WalkStructFn[Ctx] {
    // Register all fields we want to process
    for i := 0; i < typ.NumField(); i++ {
        reg.RegisterField(i)
    }

    return func(ctx Ctx, s Struct[Ctx]) error {
        for i := 0; i < s.NumFields(); i++ {
            field := s.Field(i)
            if field.IsValid() {
                field.Walk(ctx) // Walk each registered field
            }
        }
        return nil
    }
})

Values

This section outlines the values that guide type-walk's design decisions and trade-offs.

Primary Goals:

  • Performance - Fast execution with minimal allocations after initial compilation.

    • This should not be compromised for anything other than safety.
  • Safety - All unsafe operations stay internal to the library. Users should not be able to cause undefined behavior through the safe API or need to import the unsafe package.

    • There may be optional features that can be used unsafely. These should be clearly marked and require users to explicitly opt in.
  • Ease-of-use - Simple API for common use cases, with a reasonable learning curve. Code using type-walk should be readable and maintainable.

    • Convenience features should be added, even if they're not strictly necessary.

Secondary Goals:

  • Flexibility - Support varied use cases through plain Go code rather than DSLs. Enable replacement of most reflection-based value walking.

Non-priorities:

  • Simplicity - Internal code complexity is acceptable if it keeps the external API simple.

  • Backward compatibility - Breaking changes are expected during development. Pin to specific versions if stability is required.

API Reference

For complete API documentation, see pkg.go.dev.

Core Types
  • Register[Ctx] - Stores registered walk and compile functions
  • Walker[Ctx] - Compiles and executes registered functions on values
  • TypeFn[Ctx, T] - Pre-compiled function for walking values of type T
  • Arg[T] - Wrapper for values being walked (provides Get/Set methods)
Registration Functions
  • RegisterTypeFn[Ctx, T] - Register handler for specific type T
  • RegisterCompileStringFn[Ctx] - Register compile handler for string types
  • RegisterCompileStructFn[Ctx] - Register compile handler for struct types
  • Similar functions exist for Bool, Int, Slice, Array, Ptr, Map, Interface, etc.
Walk Functions
  • WalkFn[Ctx, T] - Function type for handling values of simple type T
  • WalkStructFn[Ctx] - Function type for handling struct values
  • WalkSliceFn[Ctx] - Function type for handling slice values
  • Similar types exist for Array, Ptr, Map, Interface, etc.
Abstract Walking Types
  • Struct[Ctx] - Represents a struct during walking
  • Slice[Ctx] - Represents a slice during walking
  • Ptr[Ctx] - Represents a pointer during walking
  • Similar types exist for other complex kinds

Documentation

Overview

Example (PrettyPrint)
// Ctx tracks the buffer that we're writing into, as well as the current indentation level.
// Writing errors can mostly be ignored because writing to strings.Builder cannot fail.
type Ctx struct {
	Buffer *strings.Builder
	Indent int
}

// Write N spaces to the buffer to indent correctly.
indent := func(ctx Ctx) {
	for i := 0; i < ctx.Indent; i++ {
		ctx.Buffer.WriteRune(' ')
	}
}

register := tw.NewRegister[Ctx]()

// For simple types, just serialize into the buffer.
tw.RegisterCompileBoolFn(register, func(typ reflect.Type) tw.WalkFn[Ctx, bool] {
	return func(ctx Ctx, v tw.Bool) error {
		_, err := fmt.Fprintf(ctx.Buffer, "%t", v.Get())
		return err
	}
})
tw.RegisterCompileIntFn(register, func(typ reflect.Type) tw.WalkFn[Ctx, int] {
	return func(ctx Ctx, v tw.Int) error {
		_, err := fmt.Fprintf(ctx.Buffer, "%d", v.Get())
		return err
	}
})
tw.RegisterCompileStringFn(register, func(typ reflect.Type) tw.WalkFn[Ctx, string] {
	return func(ctx Ctx, v tw.String) error {
		_, err := fmt.Fprintf(ctx.Buffer, `"%s"`, v.Get())
		return err
	}
})

// For pointers, handle nil, otherwise handle recursively.
tw.RegisterCompilePtrFn(register, func(typ reflect.Type) tw.WalkPtrFn[Ctx] {
	return func(ctx Ctx, p tw.Ptr[Ctx]) error {
		if p.IsNil() {
			_, _ = ctx.Buffer.WriteString("nil")
			return nil
		}
		return p.Walk(ctx)
	}
})

// For slices, handle each element, setting up the correct indentation.
tw.RegisterCompileSliceFn(register, func(typ reflect.Type) tw.WalkSliceFn[Ctx] {
	return func(ctx Ctx, p tw.Slice[Ctx]) error {
		if p.IsNil() {
			_, err := fmt.Fprintf(ctx.Buffer, "nil")
			return err
		}
		ctx.Buffer.WriteString("[\n")
		ctx.Indent += 2
		for i := 0; i < p.Len(); i++ {
			indent(ctx)
			err := p.Elem(i).Walk(ctx)
			if err != nil {
				return err
			}
			ctx.Buffer.WriteString("\n")
		}
		ctx.Indent -= 2
		indent(ctx)
		ctx.Buffer.WriteString("]")
		return nil
	}
})

// For structs, when compiling, register the fields and track the field names.
// When walking, handle each element, printing the correct name and setting up the correct indentation.
tw.RegisterCompileStructFn(register, func(typ reflect.Type, r tw.StructFieldRegister) tw.WalkStructFn[Ctx] {
	fieldNames := make([]string, typ.NumField())
	for i := 0; i < typ.NumField(); i++ {
		idx := r.RegisterField(i)
		fieldNames[idx] = typ.Field(i).Name
	}
	return func(ctx Ctx, s tw.Struct[Ctx]) error {
		ctx.Buffer.WriteString("{\n")
		ctx.Indent += 2
		for i := 0; i < s.NumFields(); i++ {
			indent(ctx)
			ctx.Buffer.WriteString(fieldNames[i])
			ctx.Buffer.WriteString(": ")
			err := s.Field(i).Walk(ctx)
			if err != nil {
				return err
			}
			ctx.Buffer.WriteString("\n")
		}
		ctx.Indent -= 2
		indent(ctx)
		ctx.Buffer.WriteString("}")
		return nil
	}
})

walker := tw.NewWalker[Ctx](register)

type Inner struct {
	A *int
	B bool
	C []string
}
type Outer struct {
	S []*Inner
}

ctx := Ctx{Buffer: &strings.Builder{}}
err := walker.Walk(ctx, Outer{
	S: []*Inner{
		{A: ptr(1), B: true, C: []string{"foo", "bar", "baz"}},
		nil,
		{A: nil, B: false, C: nil},
	},
})
if err != nil {
	panic(err)
}
fmt.Println(ctx.Buffer.String())
Output:
{
  S: [
    {
      A: 1
      B: true
      C: [
        "foo"
        "bar"
        "baz"
      ]
    }
    nil
    {
      A: nil
      B: false
      C: nil
    }
  ]
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func RegisterCompileArrayFn added in v0.2.0

func RegisterCompileArrayFn[Ctx any](register *Register[Ctx], fn CompileArrayFn[Ctx])

RegisterCompileArrayFn registers a compile function for types of kind Array.

func RegisterCompileBoolFn added in v0.2.0

func RegisterCompileBoolFn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, bool])

RegisterCompileBoolFn registers a compile function for types of kind Bool.

func RegisterCompileComplex64Fn added in v0.2.0

func RegisterCompileComplex64Fn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, complex64])

RegisterCompileComplex64Fn registers a compile function for types of kind Complex64.

func RegisterCompileComplex128Fn added in v0.2.0

func RegisterCompileComplex128Fn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, complex128])

RegisterCompileComplex128Fn registers a compile function for types of kind Complex128.

func RegisterCompileFloat32Fn added in v0.2.0

func RegisterCompileFloat32Fn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, float32])

RegisterCompileFloat32Fn registers a compile function for types of kind Float32.

func RegisterCompileFloat64Fn added in v0.2.0

func RegisterCompileFloat64Fn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, float64])

RegisterCompileFloat64Fn registers a compile function for types of kind Float64.

func RegisterCompileInt8Fn added in v0.2.0

func RegisterCompileInt8Fn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, int8])

RegisterCompileInt8Fn registers a compile function for types of kind Int8.

func RegisterCompileInt16Fn added in v0.2.0

func RegisterCompileInt16Fn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, int16])

RegisterCompileInt16Fn registers a compile function for types of kind Int16.

func RegisterCompileInt32Fn added in v0.2.0

func RegisterCompileInt32Fn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, int32])

RegisterCompileInt32Fn registers a compile function for types of kind Int32.

func RegisterCompileInt64Fn added in v0.2.0

func RegisterCompileInt64Fn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, int64])

RegisterCompileInt64Fn registers a compile function for types of kind Int64.

func RegisterCompileIntFn added in v0.2.0

func RegisterCompileIntFn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, int])

RegisterCompileIntFn registers a compile function for types of kind Int.

func RegisterCompileInterfaceFn added in v0.2.0

func RegisterCompileInterfaceFn[Ctx any](register *Register[Ctx], fn CompileInterfaceFn[Ctx])

RegisterCompileInterfaceFn registers a compile function for types of kind Interface.

func RegisterCompileMapFn added in v0.2.0

func RegisterCompileMapFn[Ctx any](register *Register[Ctx], fn CompileMapFn[Ctx])

RegisterCompileMapFn registers a compile function for types of kind Map.

func RegisterCompilePtrFn added in v0.2.0

func RegisterCompilePtrFn[Ctx any](register *Register[Ctx], fn CompilePtrFn[Ctx])

RegisterCompilePtrFn registers a compile function for types of kind Ptr.

func RegisterCompileSliceFn added in v0.2.0

func RegisterCompileSliceFn[Ctx any](register *Register[Ctx], fn CompileSliceFn[Ctx])

RegisterCompileSliceFn registers a compile function for types of kind Slice.

func RegisterCompileStringFn added in v0.2.0

func RegisterCompileStringFn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, string])

RegisterCompileStringFn registers a compile function for types of kind String.

func RegisterCompileStructFn added in v0.2.0

func RegisterCompileStructFn[Ctx any](register *Register[Ctx], fn CompileStructFn[Ctx])

RegisterCompileStructFn registers a compile function for types of kind Struct.

func RegisterCompileUint8Fn added in v0.2.0

func RegisterCompileUint8Fn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, uint8])

RegisterCompileUint8Fn registers a compile function for types of kind Uint8.

func RegisterCompileUint16Fn added in v0.2.0

func RegisterCompileUint16Fn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, uint16])

RegisterCompileUint16Fn registers a compile function for types of kind Uint16.

func RegisterCompileUint32Fn added in v0.2.0

func RegisterCompileUint32Fn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, uint32])

RegisterCompileUint32Fn registers a compile function for types of kind Uint32.

func RegisterCompileUint64Fn added in v0.2.0

func RegisterCompileUint64Fn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, uint64])

RegisterCompileUint64Fn registers a compile function for types of kind Uint64.

func RegisterCompileUintFn added in v0.2.0

func RegisterCompileUintFn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, uint])

RegisterCompileUintFn registers a compile function for types of kind Uint.

func RegisterCompileUintptrFn added in v0.2.0

func RegisterCompileUintptrFn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, uintptr])

RegisterCompileUintptrFn registers a compile function for types of kind Uintptr.

func RegisterCompileUnsafePointerFn added in v0.2.0

func RegisterCompileUnsafePointerFn[Ctx any](register *Register[Ctx], fn CompileFn[Ctx, unsafe.Pointer])

RegisterCompileUnsafePointerFn registers a compile function for types of kind UnsafePointer.

func RegisterTypeFn

func RegisterTypeFn[Ctx any, In any](register *Register[Ctx], fn WalkFn[Ctx, In])

RegisterTypeFn registers a function to handle type In.

Types

type Arg

type Arg[T any] struct {
	// contains filtered or unexported fields
}

Arg represents a value of a known type.

func (Arg[T]) CanSet

func (a Arg[T]) CanSet() bool

CanSet returns whether the arg is settable. Calling Set on an arg that is not settable panics.

func (Arg[T]) Get

func (a Arg[T]) Get() T

Get returns the underlying value.

func (Arg[T]) Set

func (a Arg[T]) Set(value T)

Set sets the underlying value. The arg must be settable.

type Array

type Array[Ctx any] struct {
	// contains filtered or unexported fields
}

Array represents an array value.

func (Array[Ctx]) Elem

func (a Array[Ctx]) Elem(idx int) ArrayElem[Ctx]

Elem returns an ArrayElem representing an element of the array by idx. idx must be in the range [0..Len()).

func (Array[Ctx]) Interface

func (a Array[Ctx]) Interface() any

Interface returns the underlying value as an interface.

func (Array[Ctx]) Len

func (a Array[Ctx]) Len() int

Len returns the length of the array value.

type ArrayElem

type ArrayElem[Ctx any] struct {
	// contains filtered or unexported fields
}

ArrayElem represents an element of an array.

func (ArrayElem[Ctx]) Interface

func (e ArrayElem[Ctx]) Interface() any

Interface returns the underlying value as an interface.

func (ArrayElem[Ctx]) Walk

func (e ArrayElem[Ctx]) Walk(ctx Ctx) error

Walk walks the ArrayElem.

type Bool

type Bool = Arg[bool]

type CompileArrayFn

type CompileArrayFn[Ctx any] func(reflect.Type) WalkArrayFn[Ctx]

CompileArrayFn defines the function type that will be called to generate a WalkArrayFn when an array value is encountered while walking, if a WalkFn has not already been registered.

type CompileFn

type CompileFn[Ctx any, In any] func(reflect.Type) WalkFn[Ctx, In]

CompileFn defines the function type that will be called to generate a WalkFn when a value with In's kind is encountered while walking, if a WalkFn has not already been registered.

type CompileInterfaceFn

type CompileInterfaceFn[Ctx any] func(reflect.Type) WalkInterfaceFn[Ctx]

CompileInterfaceFn defines the function type that will be called to generate a WalkInterfaceFn when an interface value is encountered while walking, if a WalkFn has not already been registered.

type CompileMapFn

type CompileMapFn[Ctx any] func(reflect.Type) WalkMapFn[Ctx]

CompileMapFn defines the function type that will be called to generate a WalkMapFn when a map value is encountered while walking, if a WalkFn has not already been registered.

type CompilePtrFn

type CompilePtrFn[Ctx any] func(reflect.Type) WalkPtrFn[Ctx]

CompilePtrFn defines the function type that will be called to generate a WalkPtrFn when a pointer value is encountered while walking, if a WalkFn has not already been registered.

type CompileSliceFn

type CompileSliceFn[Ctx any] func(reflect.Type) WalkSliceFn[Ctx]

CompileSliceFn defines the function type that will be called to generate a WalkSliceFn when a slice value is encountered while walking, if a WalkFn has not already been registered.

type CompileStructFn

type CompileStructFn[Ctx any] func(reflect.Type, StructFieldRegister) WalkStructFn[Ctx]

CompileStructFn defines the function type that will be called to generate a WalkStructFn when a struct value is encountered while walking, if a WalkFn has not already been registered.

type Complex64

type Complex64 = Arg[complex64]

type Complex128

type Complex128 = Arg[complex128]

type Float32

type Float32 = Arg[float32]

type Float64

type Float64 = Arg[float64]

type Int

type Int = Arg[int]

type Int8

type Int8 = Arg[int8]

type Int16

type Int16 = Arg[int16]

type Int32

type Int32 = Arg[int32]

type Int64

type Int64 = Arg[int64]

type Interface

type Interface[Ctx any] struct {
	// contains filtered or unexported fields
}

Interface represents an interface value.

func (Interface[Ctx]) Interface

func (i Interface[Ctx]) Interface() any

Interface returns the underlying value as an interface.

func (Interface[Ctx]) IsNil

func (i Interface[Ctx]) IsNil() bool

IsNil returns if the interface value is nil.

func (Interface[Ctx]) Walk

func (i Interface[Ctx]) Walk(ctx Ctx) error

Walk walks the concrete value of the interface by type. The interface value must not be nil.

type Map

type Map[Ctx any] struct {
	// contains filtered or unexported fields
}

Map represents a Map value.

func (Map[Ctx]) Interface

func (m Map[Ctx]) Interface() any

Interface returns the underlying value as an interface.

func (Map[Ctx]) IsNil

func (m Map[Ctx]) IsNil() bool

IsNil returns whether the map value is nil.

func (Map[Ctx]) Iter

func (m Map[Ctx]) Iter() MapIter[Ctx]

Iter returns an iterator over the elements of the map.

type MapEntry

type MapEntry[Ctx any] struct {
	// contains filtered or unexported fields
}

MapEntry represents a key and value in the map.

func (MapEntry[Ctx]) Key

func (m MapEntry[Ctx]) Key() MapKey[Ctx]

Key returns a MapKey representing a key in the map.

func (MapEntry[Ctx]) Value

func (m MapEntry[Ctx]) Value() MapValue[Ctx]

Value returns a MapValue representing a value in the map.

type MapIter

type MapIter[Ctx any] struct {
	// contains filtered or unexported fields
}

MapIter represents an iterator over the entries of the map.

func (MapIter[Ctx]) Entry

func (m MapIter[Ctx]) Entry() MapEntry[Ctx]

Entry returns a MapEntry representing a key and value in the map.

func (MapIter[Ctx]) Next

func (m MapIter[Ctx]) Next() bool

Next advances the MapIter to the next entry in the map.

type MapKey

type MapKey[Ctx any] struct {
	// contains filtered or unexported fields
}

MapKey represents a key in the map.

func (MapKey[Ctx]) Interface

func (m MapKey[Ctx]) Interface() any

Interface returns the underlying value as an interface.

func (MapKey[Ctx]) Walk

func (m MapKey[Ctx]) Walk(ctx Ctx) error

Walk walks the MapKey.

type MapValue

type MapValue[Ctx any] struct {
	// contains filtered or unexported fields
}

MapValue represents a value in the map.

func (MapValue[Ctx]) Interface

func (m MapValue[Ctx]) Interface() any

Interface returns the underlying value as an interface.

func (MapValue[Ctx]) Walk

func (m MapValue[Ctx]) Walk(ctx Ctx) error

Walk walks the MapValue.

type Ptr

type Ptr[Ctx any] struct {
	// contains filtered or unexported fields
}

Ptr represents a pointer value.

func (Ptr[Ctx]) Interface

func (p Ptr[Ctx]) Interface() any

Interface returns the underlying value as an interface.

func (Ptr[Ctx]) IsNil

func (p Ptr[Ctx]) IsNil() bool

IsNil returns if the pointer value is nil.

func (Ptr[Ctx]) Walk

func (p Ptr[Ctx]) Walk(ctx Ctx) error

Walk walks the value pointed at by the pointer value. The pointer value must not be nil.

type Register

type Register[Ctx any] struct {
	// contains filtered or unexported fields
}

Register stores a set of WalkFns used to walk specific types, and functions to compile WalkFns for kinds of types.

func NewRegister

func NewRegister[Ctx any]() *Register[Ctx]

NewRegister creates a new register.

type Slice

type Slice[Ctx any] struct {
	// contains filtered or unexported fields
}

Slice represents a slice value.

func (Slice[Ctx]) Cap

func (s Slice[Ctx]) Cap() int

Cap returns the capacity of the slice value.

func (Slice[Ctx]) Elem

func (s Slice[Ctx]) Elem(idx int) SliceElem[Ctx]

Elem returns a SliceElem representing an element of the slice by idx. idx must be in the range [0..Len()).

func (Slice[Ctx]) Interface

func (a Slice[Ctx]) Interface() any

Interface returns the underlying value as an interface.

func (Slice[Ctx]) IsNil

func (s Slice[Ctx]) IsNil() bool

IsNil returns if the slice value is nil.

func (Slice[Ctx]) Len

func (s Slice[Ctx]) Len() int

Len returns the length of the slice value.

type SliceElem

type SliceElem[Ctx any] struct {
	// contains filtered or unexported fields
}

SliceElem represents an element of an array.

func (SliceElem[Ctx]) Interface

func (e SliceElem[Ctx]) Interface() any

Interface returns the underlying value as an interface.

func (SliceElem[Ctx]) Walk

func (e SliceElem[Ctx]) Walk(ctx Ctx) error

Walk walks the SliceElem. idx must be in the range [0..Len())

type String

type String = Arg[string]

type Struct

type Struct[Ctx any] struct {
	// contains filtered or unexported fields
}

Struct represents a struct value.

func (Struct[Ctx]) Field

func (s Struct[Ctx]) Field(idx int) StructField[Ctx]

Field returns the StructField value for a registered field, by index in the order the fields were registered. idx must be in the range [0..NumFields())

func (Struct[Ctx]) Interface

func (s Struct[Ctx]) Interface() any

Interface returns the underlying value as an interface.

func (Struct[Ctx]) NumFields

func (s Struct[Ctx]) NumFields() int

NumFields returns the number of registered fields that can be walked.

type StructField

type StructField[Ctx any] struct {
	// contains filtered or unexported fields
}

StructField represents the field of a struct.

func (StructField[Ctx]) Interface

func (f StructField[Ctx]) Interface() any

Interface returns the underlying value as an interface.

func (StructField[Ctx]) IsValid

func (f StructField[Ctx]) IsValid() bool

IsValid returns true if the StructField is valid, otherwise false. Calling Walk on an invalid struct field panics.

IsValid returns false only if the field is defined on the parent struct by a multipart Index, one or more of the intermediate fields is a pointer, and one or more of the pointers used to look up the field on this value is nil. For example, in the following type, Example.F1.F2 will be invalid if Example.F1 is nil, but not if F2 is nil. Example.F3.F4 can never be invalid, because it is not referenced through a pointer (even though it is itself a pointer.)

type Example struct {
    F1 *struct {
        F2 *int
    }
    F3 struct {
        F4 *int
    }
}

func (StructField[Ctx]) Walk

func (f StructField[Ctx]) Walk(ctx Ctx) error

Walk walks the StructField. The StructField must be valid.

type StructFieldRegister

type StructFieldRegister struct {
	// contains filtered or unexported fields
}

StructFieldRegister stores information about which fields to walk within a struct.

func (StructFieldRegister) RegisterField

func (r StructFieldRegister) RegisterField(fieldNum int) int

RegisterField registers a field to be available while walking the struct, by its field number. When walking the struct, Struct.Field(n) will return nth field registered.

func (StructFieldRegister) RegisterFieldByIndex

func (r StructFieldRegister) RegisterFieldByIndex(index []int) int

RegisterFieldByIndex registers a field to be available while walking the struct, according to the Index field of the reflect.StructField representing the field.

type TypeFn

type TypeFn[Ctx any, In any] func(ctx Ctx, in *In) error

TypeFn is a function to walk a value of a particular type.

Despite taking an argument of type (*In) it is walked as a value of type In. If a function to walk a (*In) is registered, it will not be called.

func TypeFnFor

func TypeFnFor[In any, Ctx any](w *Walker[Ctx]) (TypeFn[Ctx, In], error)

TypeFnFor returns a TypeFn to walk a value of a particular type.

type Uint

type Uint = Arg[uint]

type Uint8

type Uint8 = Arg[uint8]

type Uint16

type Uint16 = Arg[uint16]

type Uint32

type Uint32 = Arg[uint32]

type Uint64

type Uint64 = Arg[uint64]

type Uintptr

type Uintptr = Arg[uintptr]

type UnsafePointer

type UnsafePointer = Arg[unsafe.Pointer]

type WalkArrayFn

type WalkArrayFn[Ctx any] func(Ctx, Array[Ctx]) error

WalkArrayFn defines the function that will be called when an array value is encountered while walking.

func ReturnErrArrayFn

func ReturnErrArrayFn[Ctx any](err error) WalkArrayFn[Ctx]

ReturnErrArrayFn returns a WalkArrayFn that returns the given error.

This is intended to be used when a CompileArrayFn encounters an error.

type WalkFn

type WalkFn[Ctx any, In any] func(Ctx, Arg[In]) error

WalkFn defines the function that will be called when a value of type In is encountered while walking.

func ReturnErrFn

func ReturnErrFn[Ctx any, In any](err error) WalkFn[Ctx, In]

ReturnErrFn returns a WalkFn that returns the given error.

This is intended to be used when a CompileFn encounters an error.

type WalkInterfaceFn

type WalkInterfaceFn[Ctx any] func(Ctx, Interface[Ctx]) error

WalkInterfaceFn defines the function that will be called when an interface value is encountered while walking.

func ReturnErrInterfaceFn

func ReturnErrInterfaceFn[Ctx any](err error) WalkInterfaceFn[Ctx]

ReturnErrInterfaceFn returns a WalkInterfaceFn that returns the given error.

This is intended to be used when a CompileInterfaceFn encounters an error.

type WalkMapFn

type WalkMapFn[Ctx any] func(Ctx, Map[Ctx]) error

WalkMapFn defines the function that will be called when a map value is encountered while walking.

func ReturnErrMapFn

func ReturnErrMapFn[Ctx any](err error) WalkMapFn[Ctx]

ReturnErrMapFn returns a WalkMapFn that returns the given error.

This is intended to be used when a CompileMapFn encounters an error.

type WalkPtrFn

type WalkPtrFn[Ctx any] func(Ctx, Ptr[Ctx]) error

WalkPtrFn defines the function that will be called when a pointer value is encountered while walking.

func ReturnErrPtrFn

func ReturnErrPtrFn[Ctx any](err error) WalkPtrFn[Ctx]

ReturnErrPtrFn returns a WalkPtrFn that returns the given error.

This is intended to be used when a CompilePtrFn encounters an error.

type WalkSliceFn

type WalkSliceFn[Ctx any] func(Ctx, Slice[Ctx]) error

WalkSliceFn defines the function that will be called when a slice value is encountered while walking.

func ReturnErrSliceFn

func ReturnErrSliceFn[Ctx any](err error) WalkSliceFn[Ctx]

ReturnErrSliceFn returns a WalkSliceFn that returns the given error.

This is intended to be used when a CompileSliceFn encounters an error.

type WalkStructFn

type WalkStructFn[Ctx any] func(Ctx, Struct[Ctx]) error

WalkStructFn defines the function that will be called when a struct value is encountered while walking.

func ReturnErrStructFn

func ReturnErrStructFn[Ctx any](err error) WalkStructFn[Ctx]

ReturnErrStructFn returns a WalkStructFn that returns the given error.

This is intended to be used when a CompileStructFn encounters an error.

type Walker

type Walker[Ctx any] struct {
	// contains filtered or unexported fields
}

Walker represents a collection of functions that can be used to walk a value using the Walk method.

func NewWalker

func NewWalker[Ctx any](register *Register[Ctx], opts ...WalkerOpt) *Walker[Ctx]

NewWalker creates a new Walker from the registered functions in register. Any new functions that are added to the register after calling NewWalker will not be used by the returned Walker.

func (*Walker[Ctx]) Walk

func (w *Walker[Ctx]) Walk(ctx Ctx, in any) error

Walk walks in, calling the registered for each value it encounters.

type WalkerOpt

type WalkerOpt func(*walkerConfig)

WalkerOpt is an option to configure a new walker.

var (
	// WithThreadSafe makes a Walker safe to use concurrently.
	WithThreadSafe WalkerOpt = func(w *walkerConfig) {
		w.threadSafe = true
	}
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL