decoder

package
v0.18.0 Latest Latest
Warning

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

Go to latest
Published: May 20, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package decoder turns bytes of various encodings (yaml/json/...) into a uniform map[string]any intermediate representation. That representation lives only inside the reload pipeline and never appears in the public API.

Decoders are registered through a process-wide registry (see registry.go). The built-in yaml/yml/json codecs register themselves in init(); external codecs (toml/hcl/json5/...) plug in from outside the repo via fastconf.RegisterCodec.

Typed decoder hooks.

FastConf's default decode path round-trips merged maps through encoding/json. That keeps the canonical byte stream coherent with the SHA-256 hash used for dedupe, but encoding/json refuses common "human-readable string → typed value" conversions: "30s" cannot land in a time.Duration, "10.0.0.1" cannot land in net.IP, etc.

TypedHook is a small, opt-in pre-decode rewrite step. BuildTypedPlan inspects *T once at construction and emits a tree describing which leaves carry hook-eligible types and which map-key candidates they can appear under (json tag, lowercase field name, struct field name). Apply walks both the merged map and the plan tree together so it works regardless of whether the source codec wrote canonical-JSON keys or YAML-flavoured lowercase keys.

Built-in TypedHook implementations.

Index

Constants

This section is empty.

Variables

View Source
var ErrUnknownCodec = errors.New("decoder: unknown codec")

ErrUnknownCodec means the codec name was not registered.

Functions

func CodecFromExt

func CodecFromExt(ext string) string

CodecFromExt infers a codec name from a file extension (with or without the leading dot). Returns empty string when the extension is unrecognised. Queries only codecs registered via RegisterCodec/RegisterCodecExt.

func DecodeAny

func DecodeAny(codec string, data []byte) (any, error)

DecodeAny decodes data as either an object or an array (used for RFC 6902 patch layers whose top-level node is an array). Returns either map[string]any or []any. Returns nil on empty input.

func Lookup

func Lookup(name string) (contracts.Codec, bool)

Lookup returns the codec for name (case-insensitive) along with an "exists" flag. Used by tests to assert registration ordering.

func LookupExt

func LookupExt(ext string) string

LookupExt returns the codec name for a given extension, or "" if the extension is unknown.

func Register

func Register(name string, c contracts.Codec)

Register installs c under the given name (case-insensitive). It is safe for concurrent use. Registering nil panics; that signals a bug at init time and we prefer to fail loudly rather than silently dropping the codec on first use. Re-registering an existing name overwrites it, which makes test helpers and feature toggles ergonomic.

func RegisterExt

func RegisterExt(ext, codec string)

RegisterExt maps a file extension (with or without leading dot, case insensitive) to a codec name. It does NOT register the codec itself — the caller should also call Register if the codec is custom.

Types

type Decoder

type Decoder = contracts.Codec

Decoder turns a byte stream into a generic map.

Decoder is an alias for the public contracts.Codec interface, so any implementation of contracts.Codec can be fed directly into this package's registry.

func For

func For(codec string) (Decoder, error)

For returns the Decoder for a codec name. Codec lookup is case insensitive. Returns ErrUnknownCodec when the codec is not registered.

type DurationHook

type DurationHook struct{}

DurationHook: "30s" → int64(30 * time.Second).

func (DurationHook) Convert

func (DurationHook) Convert(raw any) (any, error)

func (DurationHook) Match

func (DurationHook) Match(t reflect.Type) bool

type IPHook

type IPHook struct{}

IPHook: "10.0.0.1" → canonical string accepted by net.IP JSON unmarshal.

func (IPHook) Convert

func (IPHook) Convert(raw any) (any, error)

func (IPHook) Match

func (IPHook) Match(t reflect.Type) bool

type RegexHook

type RegexHook struct{}

RegexHook: validates the pattern then passes through.

func (RegexHook) Convert

func (RegexHook) Convert(raw any) (any, error)

func (RegexHook) Match

func (RegexHook) Match(t reflect.Type) bool

type StringPrimitiveHook added in v0.18.0

type StringPrimitiveHook struct{}

StringPrimitiveHook converts string raw values into the primitive kind expected by the destination struct field: bool, int family, uint family, or float family. Named primitive types (e.g. time.Duration) are deliberately skipped so dedicated hooks (DurationHook) win the dispatch instead.

The hook is a no-op when the raw value is not a string, so YAML/JSON layers that already decoded values to typed forms pass through unchanged. It is registered in DefaultTypedHooks so the typical "env value lands in a typed struct field" path works out of the box.

func (StringPrimitiveHook) Convert added in v0.18.0

func (StringPrimitiveHook) Convert(raw any) (any, error)

Convert without a target type cannot pick a parse strategy, so it returns raw untouched. The walker uses ConvertWithTarget when the plan node records a target type.

func (StringPrimitiveHook) ConvertWithTarget added in v0.18.0

func (StringPrimitiveHook) ConvertWithTarget(raw any, target reflect.Type) (any, error)

ConvertWithTarget parses the string into the requested kind. Non-string raw values pass through unchanged.

func (StringPrimitiveHook) Match added in v0.18.0

Match accepts unnamed (builtin) primitive numeric / bool types. Named types (PkgPath != "") are excluded so DurationHook and similar keep their precedence.

type TypedHook

type TypedHook interface {
	// Match reports whether this hook applies to the given destination
	// field type. The walker calls Match once per leaf, cached by type.
	Match(t reflect.Type) bool
	// Convert turns the raw value (usually string) into a value the
	// JSON decoder can natively assign to the target type. Returning
	// (raw, nil) leaves the value untouched.
	Convert(raw any) (any, error)
}

TypedHook converts a raw value into the typed representation that encoding/json round-trip expects for a specific field type.

func DefaultTypedHooks

func DefaultTypedHooks() []TypedHook

DefaultTypedHooks returns the built-in hook set. Hook implementations and ordering are defined in typed_hooks_defaults.go. DurationHook is registered first so named primitive types win dispatch over the generic StringPrimitiveHook. Install additional hooks via WithTypedHook.

type TypedHookPlan

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

TypedHookPlan is a struct-shaped plan: each node mirrors a struct field and records which map-key aliases the merged map might use (json tag, yaml tag, lowercase name, exact field name).

func BuildTypedHookPlan

func BuildTypedHookPlan(t reflect.Type, hooks []TypedHook) *TypedHookPlan

BuildTypedHookPlan inspects t and returns a plan that the walker can apply against any merged map. Pointer/elem unwrapping is automatic.

func (*TypedHookPlan) Apply

func (p *TypedHookPlan) Apply(merged map[string]any) error

Apply rewrites every hook-eligible leaf in merged. Returns the first conversion error encountered.

type TypedHookWithTarget added in v0.18.0

type TypedHookWithTarget interface {
	TypedHook
	ConvertWithTarget(raw any, target reflect.Type) (any, error)
}

TypedHookWithTarget is an optional extension to TypedHook. When a hook implements this interface, the walker calls ConvertWithTarget(raw, target) instead of Convert(raw), passing the destination field's reflect.Type. This is required for hooks that handle a family of kinds (e.g. StringPrimitiveHook) and need the target type to pick the right parse strategy.

type URLHook

type URLHook struct{}

URLHook: round-trips a URL string after validating.

func (URLHook) Convert

func (URLHook) Convert(raw any) (any, error)

func (URLHook) Match

func (URLHook) Match(t reflect.Type) bool

Jump to

Keyboard shortcuts

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