engine

package
v6.0.0 Latest Latest
Warning

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

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

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ApplyOpReflection

func ApplyOpReflection[T any](target *T, op Operation, logger *slog.Logger) error

ApplyOpReflection applies a single operation to target using reflection. It is called by generated Patch methods for operations the generated fast-path does not handle (e.g. slice index or map key paths). Direct use is not intended.

func ApplyOpReflectionValue

func ApplyOpReflectionValue(v reflect.Value, op Operation, logger *slog.Logger) error

ApplyOpReflectionValue applies op to the already-reflected value v.

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 Equal

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

Equal performs a deep equality check between a and b. It supports cyclic references and unexported fields. You can customize behavior using EqualOption (e.g., IgnorePath).

func IgnorePath

func IgnorePath(path string) interface {
	DiffOption
	CopyOption
	EqualOption
}

IgnorePath returns an option that tells Diff, Copy, and Equal to ignore changes at the specified path. The path should use JSON Pointer notation (e.g., "/Field/SubField", "/Map/Key", "/Slice/0").

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 RegisterCustomCopy

func RegisterCustomCopy[T any](fn func(T) (T, error))

RegisterCustomCopy registers a custom copy function for a specific type.

func RegisterCustomDiff

func RegisterCustomDiff[T any](fn func(a, b T) (Patch[T], error))

RegisterCustomDiff registers a custom diff function for a specific type globally.

func RegisterCustomEqual

func RegisterCustomEqual[T any](fn func(T, T) bool)

RegisterCustomEqual registers a custom equality function for a specific type.

Types

type ApplyError

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

ApplyError represents one or more errors that occurred during patch application.

func (*ApplyError) Error

func (e *ApplyError) Error() string

func (*ApplyError) Errors

func (e *ApplyError) Errors() []error

func (*ApplyError) Unwrap

func (e *ApplyError) Unwrap() []error

type ConflictResolver

type ConflictResolver interface {
	// Resolve allows the resolver to intervene before an operation is applied.
	// It returns the value to be applied and true if the operation should proceed,
	// or the zero reflect.Value and false to skip it.
	Resolve(path string, op OpKind, key, prevKey any, current, proposed reflect.Value) (reflect.Value, bool)
}

ConflictResolver allows custom logic to be injected during patch application. It is used to implement CRDTs, 3-way merges, and other conflict resolution strategies.

type Copier

type Copier[T any] interface {
	Copy() (T, error)
}

Copier is an interface that types can implement to provide their own custom deep copy logic.

type CopyOption

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

CopyOption allows configuring the behavior of the Copy function.

func SkipUnsupported

func SkipUnsupported() CopyOption

SkipUnsupported returns an option that tells Copy to skip unsupported types.

type DiffOption

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

DiffOption allows configuring the behavior of the Diff function.

func DiffDetectMoves

func DiffDetectMoves(enable bool) DiffOption

DiffDetectMoves returns an option that enables move and copy detection.

type Differ

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

Differ is a stateless engine for calculating patches between two values.

func NewDiffer

func NewDiffer(opts ...DiffOption) *Differ

NewDiffer creates a new Differ with the given options.

type EqualOption

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

EqualOption allows configuring the behavior of the Equal function.

type Keyer

type Keyer interface {
	CanonicalKey() any
}

Keyer is an interface that types can implement to provide a canonical representation for map keys. This allows semantic equality checks for complex map keys.

type OpKind

type OpKind string

OpKind is the type of an operation in a patch. It is a string, and the string is the wire form: a serialized operation says "replace", not a number whose meaning depends on the order the kinds were declared in. That also makes the zero value invalid rather than silently meaning add.

const (
	OpAdd     OpKind = "add"
	OpRemove  OpKind = "remove"
	OpReplace OpKind = "replace"
	OpMove    OpKind = "move"
	OpCopy    OpKind = "copy"
	OpLog     OpKind = "log"
	// OpAlias makes Path hold the same object From resolves to — sharing,
	// where OpCopy makes an independent deep copy. Diff emits it for the
	// second and later routes to a value that is referenced more than once, so
	// applying the patch rebuilds the sharing the new value has.
	OpAlias OpKind = "alias"
)

func (OpKind) String

func (k OpKind) String() string

func (*OpKind) UnmarshalJSON

func (k *OpKind) UnmarshalJSON(data []byte) error

UnmarshalJSON accepts the string form, and also the small integers v5 wrote — a patch stored before the change should still be readable, even though v6 will never write one like it.

type Operation

type Operation struct {
	Kind   OpKind               `json:"k"`
	Path   string               `json:"p"`
	From   string               `json:"f,omitempty"`
	Old    any                  `json:"o,omitempty"`
	New    any                  `json:"n,omitempty"`
	If     *condition.Condition `json:"if,omitempty"`
	Unless *condition.Condition `json:"un,omitempty"`
	// Strict is stamped from Patch.Strict at apply time; not serialized.
	Strict bool `json:"-"`
}

Operation represents a single change within a Patch.

Field semantics by Kind:

  • OpAdd: Path = target; New = added value.
  • OpRemove: Path = target; Old = removed value (prior).
  • OpReplace: Path = target; Old = prior value; New = replacement.
  • OpMove: Path = destination; From = source path; Old = displaced value at Path (optional).
  • OpCopy: Path = destination; From = source path; Old = displaced value at Path (optional).
  • OpLog: Path = scope; New = log message.

Old for OpMove/OpCopy was previously the source-path string; that role now belongs to From, freeing Old to carry the prior destination value (necessary for full Reverse fidelity when the destination was non-empty).

func (*Operation) GobDecode

func (op *Operation) GobDecode(data []byte) error

GobDecode is the inverse of GobEncode.

func (Operation) GobEncode

func (op Operation) GobEncode() ([]byte, error)

GobEncode carries the operation as its JSON form. Gob's own encoding of an `any` field needs every concrete type registered up front, cannot encode a nil pointer inside an interface, and does not distinguish a nil slice from an empty one; the JSON form has none of those constraints, and decodes at apply time against the target field's real type like any other wire arrival.

func (Operation) MarshalJSON

func (op Operation) MarshalJSON() ([]byte, error)

MarshalJSON writes the operation with Old and New in their encoded form — which, for values that arrived encoded, is the very bytes they arrived as.

func (*Operation) UnmarshalJSON

func (op *Operation) UnmarshalJSON(data []byte) error

UnmarshalJSON reads an operation, keeping Old and New encoded as RawValue rather than decoding them into whatever the decoder's untyped defaults are. They are decoded at apply time, against the type of the field the operation actually addresses.

type Patch

type Patch[T any] interface {
	fmt.Stringer

	// Apply applies the patch to the value pointed to by v.
	// The value v must not be nil.
	Apply(v *T)

	// ApplyChecked applies the patch only if specific conditions are met.
	// If Strict mode is enabled, every modification must match the 'oldVal' recorded in the patch.
	ApplyChecked(v *T) error

	// ApplyResolved applies the patch using a custom ConflictResolver.
	// This is used for convergent synchronization (CRDTs).
	ApplyResolved(v *T, r ConflictResolver) error

	// Walk calls fn for every operation in the patch.
	// The path is a JSON Pointer dot-notation path (e.g. "/Field/SubField/0").
	// If fn returns an error, walking stops and that error is returned.
	Walk(fn func(path string, op OpKind, old, new any) error) error

	// AsStrict returns a new Patch with strict mode enabled.
	AsStrict() Patch[T]

	// Reverse returns a new Patch that undoes the changes in this patch.
	Reverse() Patch[T]

	// ToJSONPatch returns an RFC 6902 compliant JSON Patch representation of this patch.
	ToJSONPatch() ([]byte, error)

	// Summary returns a human-readable summary of the changes in the patch.
	Summary() string
}

Patch represents a set of changes that can be applied to a value of type T.

func Diff

func Diff[T any](a, b T, opts ...DiffOption) (Patch[T], error)

Diff compares two values a and b and returns a Patch that can be applied. It returns an error if the comparison fails (e.g., due to custom diff failure).

func DiffUsing

func DiffUsing[T any](d *Differ, a, b T) (Patch[T], error)

DiffUsing compares two values a and b using the specified Differ and returns a Patch.

func MustDiff

func MustDiff[T any](a, b T, opts ...DiffOption) Patch[T]

MustDiff compares two values a and b and returns a Patch that can be applied. It panics if the comparison fails.

type RawValue

type RawValue = icore.RawValue

RawValue is a value that arrived over the wire and has not been decoded yet. See icore.RawValue.

Jump to

Keyboard shortcuts

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