core

package
v6.5.0 Latest Latest
Warning

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

Go to latest
Published: Sep 8, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildPath added in v6.2.0

func BuildPath(parts []PathPart) string

BuildPath renders path parts back into a JSON Pointer.

func CompareValues

func CompareValues(v1, v2 reflect.Value, op string, ignoreCase bool) (bool, error)

func ConvertValue

func ConvertValue(v reflect.Value, targetType reflect.Type) reflect.Value

func ConvertValueChecked

func ConvertValueChecked(v reflect.Value, targetType reflect.Type) (reflect.Value, error)

ConvertValueChecked is ConvertValue with a verdict: it reports an error instead of handing back a value the caller would panic on when setting. Patch values routinely come from untrusted input (a JSON document from a peer), so a type mismatch has to be an error, never a panic.

func ConvertValueVerified

func ConvertValueVerified(v reflect.Value, targetType reflect.Type) (reflect.Value, bool)

ConvertValueVerified converts v to targetType, refusing conversions that lose information.

Only a numeric conversion needs verifying, and it needs it badly: float64(5.7) converts to int(5), which would otherwise pass for a field holding 5. Converting back has to reproduce what was given. The other conversions this performs are not reversible and do not need to be — a map[string]any decoding into a struct has no meaningful conversion back, and no truncation to hide: the decode either produces the value or it fails.

func Copy

func Copy[T any](src T, opts ...CopyOption) (T, error)

Copy creates a deep copy of src. It returns the copy and a nil error in case of success and the zero value for the type and a non-nil error on failure.

It correctly handles cyclic references and unexported fields.

func CopyShared

func CopyShared(src any, pointers PointersMap) (any, error)

CopyShared deep-copies src recording into (and honouring) the caller's pointers map instead of a private one. Passing the same map across several copies makes them one copy for sharing purposes: a value any of them has already copied is reused, not copied again. Generated Clone code threads its memo through here for the fields it cannot copy itself.

func DeepCopyValue

func DeepCopyValue(v reflect.Value) reflect.Value

func Dereference

func Dereference(v reflect.Value) (reflect.Value, error)

func Equal

func Equal[T any](a, b T, opts ...EqualOption) bool

Equal performs a deep equality check between a and b.

func EqualCoerced

func EqualCoerced(current reflect.Value, expected any) bool

EqualCoerced reports whether current equals expected, where expected may be of a different but losslessly convertible type.

Operation.Old and a condition's Value are declared `any`, so a patch that travelled as JSON carries whatever the decoder produced: every number arrives as float64 regardless of the field's type. Comparing those with Equal, which requires identical types, reports a mismatch for every numeric field — which is why a strict check on a decoded patch used to fail against state it actually matched.

Converting before comparing fixes that, but a bare conversion truncates: float64(5.7) becomes int(5), which would then compare equal to a field holding 5. The conversion is therefore verified by converting back — only a value that survives the round trip unchanged is accepted as comparable.

func EqualCoercedValue

func EqualCoercedValue(current, ev reflect.Value) bool

EqualCoercedValue is EqualCoerced over two reflect.Values. Conditions use it so that == and != mean the same thing there as in a strict check.

func EscapeKey

func EscapeKey(key string) string

func ExtractKey

func ExtractKey(v reflect.Value, fieldIdx int) any

func FamiliesRegistered added in v6.1.0

func FamiliesRegistered() bool

FamiliesRegistered reports whether any family exists, so hot paths can skip family handling entirely in the common case of none.

func GetKeyField

func GetKeyField(typ reflect.Type) (int, bool)

func JoinPath

func JoinPath(parent, child string) string

JoinPath joins two JSON Pointer paths with a slash.

func MustCopy

func MustCopy[T any](src T, opts ...CopyOption) T

MustCopy creates a deep copy of src. It returns the copy on success or panics in case of any failure.

It correctly handles cyclic references and unexported fields.

func NormalizePath

func NormalizePath(path string) string

NormalizePath converts a dot-notation or JSON Pointer path to a standard JSON Pointer.

func RegisterCustomCopy

func RegisterCustomCopy(typ reflect.Type, fn reflect.Value)

RegisterCustomCopy registers a custom copy function for a specific type. The function must be of type func(src T) (T, error).

func RegisterCustomEqual

func RegisterCustomEqual(typ reflect.Type, fn reflect.Value)

RegisterCustomEqual registers a custom equality function for a specific type. The function must be of type func(a, b T) bool.

func RegisterFamily added in v6.1.0

func RegisterFamily(f Family)

RegisterFamily adds a family. Families are consulted in registration order; the first whose Match accepts a type owns it.

Registration is global and should happen during initialisation: registering is safe against concurrent use, but the verdict cache means a type seen before the registration keeps its earlier verdict.

func SetValue

func SetValue(v, newVal reflect.Value)

func UnescapeKey

func UnescapeKey(token string) string

UnescapeKey reverses EscapeKey, turning the RFC 6901 escape sequences "~1" and "~0" back into "/" and "~". The order (slash first) matters: unescaping "~0" first would turn "~01" into "~1" and then wrongly into "/".

func ValueEqual

func ValueEqual(a, b reflect.Value, config *equalConfig) bool

ValueEqual performs a deep equality check between two reflect.Values.

func ValueToInterface

func ValueToInterface(v reflect.Value) any

Types

type Copier

type Copier[T any] interface {
	// Copy returns a deep copy of the receiver.
	Copy() (T, error)
}

Copier is an interface that types can implement to provide their own custom deep copy logic. The type T in Copy() (T, error) must be the same concrete type as the receiver that implements this interface.

type CopyOption

type CopyOption interface {
	// contains filtered or unexported methods
}

CopyOption allows configuring the behavior of the Copy function.

func CopyIgnorePath

func CopyIgnorePath(path string) CopyOption

CopyIgnorePath returns an option that tells Copy to ignore the specified path. The ignored path will have the zero value for its type in the resulting copy.

func SkipUnsupported

func SkipUnsupported() CopyOption

SkipUnsupported returns an option that tells Copy to skip unsupported types (like non-nil functions or channels) instead of returning an error.

type DeepPath

type DeepPath string

DeepPath represents a path to a field or element within a structure. It supports JSON Pointers (RFC 6901) syntax like "/Field/SubField".

func (DeepPath) Delete

func (p DeepPath) Delete(v reflect.Value) error

func (DeepPath) Navigate

func (p DeepPath) Navigate(v reflect.Value, parts []PathPart) (reflect.Value, PathPart, error)

func (DeepPath) Resolve

func (p DeepPath) Resolve(v reflect.Value) (reflect.Value, error)

Resolve traverses v using the path and returns the reflect.Value found.

func (DeepPath) ResolveMember

func (p DeepPath) ResolveMember(v reflect.Value) (reflect.Value, error)

ResolveMember resolves the path to the member the last segment names — the struct field, map value, or slice element itself — without dereferencing it. Resolve returns the value a pointer member points at; alias operations need the pointer, because their whole purpose is to install that same reference somewhere else.

func (DeepPath) ResolveParent

func (p DeepPath) ResolveParent(v reflect.Value) (reflect.Value, PathPart, error)

func (DeepPath) ResolveParentPath

func (p DeepPath) ResolveParentPath() (DeepPath, PathPart, error)

ResolveParentPath splits the path into parent path and the last part.

func (DeepPath) Set

func (p DeepPath) Set(v reflect.Value, val reflect.Value) error

type EqualOption

type EqualOption interface {
	// contains filtered or unexported methods
}

EqualOption allows configuring the behavior of the Equal function.

func EqualIgnorePath

func EqualIgnorePath(path string) EqualOption

EqualIgnorePath returns an option that tells Equal to ignore the specified path.

type Family added in v6.1.0

type Family struct {
	// Name identifies the family in errors and diagnostics.
	Name string
	// Match reports whether t belongs to the family. It is consulted once per
	// type; the verdict is cached.
	Match func(t reflect.Type) bool
	// Equal reports whether two values of a matched type are equal. a and b
	// are the values as they appear (for pointer types, the pointers).
	Equal func(a, b any) bool
	// Clone returns a deep copy of a matched value.
	Clone func(v any) any
	// Marshal renders a matched value into its wire (JSON) form, and Unmarshal
	// reverses it for the given matched type. They exist because a family's
	// values may have a wire form encoding/json cannot produce — a protobuf
	// Timestamp is an RFC 3339 string under protojson, not a struct.
	Marshal   func(v any) ([]byte, error)
	Unmarshal func(data []byte, t reflect.Type) (any, error)
	// Resolve reads the value at a path inside a matched value, path relative
	// to it. It is what lets a condition look into the value — the generic
	// navigator stops at the family boundary the same way apply does, and
	// hands the rest of the path here. An error means the path holds nothing,
	// which an exists condition reports as false.
	Resolve func(v any, path string) (any, error)
}

Family is the core-facing part of a registered type family.

func FamilyFor added in v6.1.0

func FamilyFor(t reflect.Type) (*Family, bool)

FamilyFor returns the family owning t, if any.

type FieldInfo

type FieldInfo struct {
	Index   int
	Name    string
	JSONTag string
	Tag     StructTag
}

type PathPart

type PathPart struct {
	Key     string
	Index   int
	IsIndex bool
}

func ParseJSONPointer

func ParseJSONPointer(path string) []PathPart

func ParsePath

func ParsePath(path string) []PathPart

ParsePath parses a JSON Pointer path (RFC 6901).

type PointersMap

type PointersMap map[PointersMapKey]reflect.Value

PointersMap records the copy made for each value during one deep copy. It is exported so a copy can be run against a caller-provided map: generated Clone code and the reflection engine share one map, which is what keeps a value referenced from both sides copied exactly once.

type PointersMapKey

type PointersMapKey struct {
	Ptr uintptr
	Typ reflect.Type
}

PointersMapKey identifies one already-copied value: the address it lives at and the type it was reached as. The type matters because pointers of different types can share an address — a struct and its first field — and must not be mistaken for one another.

type RawValue

type RawValue struct {
	JSON []byte
}

RawValue holds a value that arrived over the wire and has not been decoded yet, because the right type to decode it into is not known until the operation carrying it reaches its target field.

This is what removes a whole class of coercion bugs. Decoding an untyped value produces whatever the decoder's defaults are — every JSON number a float64, every object a map[string]any, every []byte a base64 string — and the library then had to guess its way back to the field's real type, verified conversion by verified conversion, each one a place to be wrong. Decoding into the field's actual type instead makes the decoder itself do the right thing by construction.

func (RawValue) Decode

func (r RawValue) Decode(t reflect.Type) (reflect.Value, error)

Decode unmarshals the value into t, returning the decoded value.

func (RawValue) MarshalJSON

func (r RawValue) MarshalJSON() ([]byte, error)

MarshalJSON emits the still-encoded bytes as they are, so a re-serialized operation is byte-identical to the one that arrived.

func (RawValue) String added in v6.4.0

func (r RawValue) String() string

String renders the still-encoded value as its JSON text, so operations that crossed the wire print legibly — "ana", not a slice of byte values.

func (*RawValue) UnmarshalJSON

func (r *RawValue) UnmarshalJSON(data []byte) error

UnmarshalJSON captures the encoded bytes without interpreting them.

type StructTag

type StructTag struct {
	Ignore   bool
	ReadOnly bool
	Atomic   bool
	Key      bool
}

func ParseTag

func ParseTag(field reflect.StructField) StructTag

type TypeInfo

type TypeInfo struct {
	Fields        []FieldInfo
	KeyFieldIndex int
}

func GetTypeInfo

func GetTypeInfo(typ reflect.Type) *TypeInfo

type VisitKey

type VisitKey struct {
	A, B uintptr
	Typ  reflect.Type
}

Jump to

Keyboard shortcuts

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