Documentation
¶
Index ¶
- func ApplyOpReflection[T any](target *T, op Operation, logger *slog.Logger) error
- func ApplyOpReflectionValue(v reflect.Value, op Operation, logger *slog.Logger) error
- func Copy[T any](src T, opts ...CopyOption) (T, error)
- func Equal[T any](a, b T, opts ...EqualOption) bool
- func IgnorePath(path string) interface{ ... }
- func MustCopy[T any](src T, opts ...CopyOption) T
- func RegisterCustomCopy[T any](fn func(T) (T, error))
- func RegisterCustomDiff[T any](fn func(a, b T) (Patch[T], error))
- func RegisterCustomEqual[T any](fn func(T, T) bool)
- func RegisterFamilyOps(name string, diff func(a, b any) ([]Operation, error), ...)
- type ApplyError
- type ConflictResolver
- type Copier
- type CopyOption
- type DiffOption
- type Differ
- type EqualOption
- type Keyer
- type OpKind
- type Operation
- type Patch
- type RawValue
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ApplyOpReflection ¶
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 ¶
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 ¶
RegisterCustomCopy registers a custom copy function for a specific type.
func RegisterCustomDiff ¶
RegisterCustomDiff registers a custom diff function for a specific type globally.
func RegisterCustomEqual ¶
RegisterCustomEqual registers a custom equality function for a specific type.
func RegisterFamilyOps ¶ added in v6.1.0
func RegisterFamilyOps(name string, diff func(a, b any) ([]Operation, error), apply func(target any, op Operation) error)
RegisterFamilyOps installs the diff and apply handlers for the named family, which must also be registered with the core half under the same name.
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 ¶
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) UnmarshalJSON ¶
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) GobEncode ¶
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 ¶
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 ¶
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 ¶
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 ¶
RawValue is a value that arrived over the wire and has not been decoded yet. See icore.RawValue.