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 ¶
- Variables
- func CodecFromExt(ext string) string
- func DecodeAny(codec string, data []byte) (any, error)
- func Lookup(name string) (contracts.Codec, bool)
- func LookupExt(ext string) string
- func Register(name string, c contracts.Codec)
- func RegisterExt(ext, codec string)
- type Decoder
- type DurationHook
- type IPHook
- type RegexHook
- type StringPrimitiveHook
- type TypedHook
- type TypedHookPlan
- type TypedHookWithTarget
- type URLHook
Constants ¶
This section is empty.
Variables ¶
var ErrUnknownCodec = errors.New("decoder: unknown codec")
ErrUnknownCodec means the codec name was not registered.
Functions ¶
func CodecFromExt ¶
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 ¶
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 ¶
Lookup returns the codec for name (case-insensitive) along with an "exists" flag. Used by tests to assert registration ordering.
func LookupExt ¶
LookupExt returns the codec name for a given extension, or "" if the extension is unknown.
func Register ¶
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 ¶
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.
type IPHook ¶
type IPHook struct{}
IPHook: "10.0.0.1" → canonical string accepted by net.IP JSON unmarshal.
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
ConvertWithTarget parses the string into the requested kind. Non-string raw values pass through unchanged.
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.
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.