gen

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: 7 Imported by: 0

Documentation

Overview

Package gen holds the bookkeeping that code generated by deep-gen threads through its methods: a memo of copies already made, and the visited sets that keep a comparison or a diff from following a cycle forever.

It exists so that the deep package documents what a user calls. Nothing here is meant to be called by hand — a generated Clone creates its own memo, uses it, and releases it — but it has to be exported, because generated code lives in your package rather than in this one.

The deep package keeps aliases for everything here, so generated code written against an earlier version still compiles.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ApplyOpReflection

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

ApplyOpReflection applies a single operation to target through the reflection engine.

A generated Patch method calls this for the operations its fast path does not model — a slice-index path, a move or a copy, a strict check on a map entry. It is exported for that reason alone; use deep.Apply.

func CloneShared

func CloneShared[T any](v T, memo *CloneMemo) T

CloneShared deep-copies v through the reflection engine, recording into (and honouring) memo. Generated Clone methods use it for the fields they cannot copy themselves — types from other packages, interfaces, generics — so that a value shared between such a field and the rest of the struct is still copied once, wherever it was reached first.

With a nil memo it behaves like Clone.

func DiffOpaque added in v6.3.0

func DiffOpaque(path string, a, b any) []engine.Operation

DiffOpaque diffs one field the generator cannot see inside — a type from another package, an interface, a generic instantiation — rooted at path.

When a type family owns the value, the result is the family's own operations: a one-field change to a protobuf message held by a generated struct becomes one operation naming that field, where the generated code previously replaced the whole message. Otherwise it is what the generated code always did: nothing when the values are equal, one whole-value replace when they differ.

func SortOperations

func SortOperations(ops []engine.Operation)

SortOperations orders operations by path.

Generated diff code brackets the operations one map field produced and sorts that range, rather than sorting the map's keys before iterating. Go randomises map iteration, so something has to impose an order; doing it here costs one sort over the entries that actually changed, where sorting keys first costs a slice, a sort and an extra lookup for every entry in the map, changed or not.

Entries of a map are independent, so reordering the operations between them cannot change what applying them does.

Types

type CloneMemo

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

CloneMemo records the copy made for each value during a single deep copy, so that a value reached more than once is copied once and every reference to it in the result points at that one copy.

Generated Clone methods create and thread a memo when values of the type can hold two references to the same value — through a cycle, or simply through two routes to one pointer. Types where that cannot happen never allocate one.

The memo shares its identity space with the reflection engine: fields that generated code hands to CloneShared record their copies in the same map, so a value referenced from both sides is still copied exactly once.

A memo belongs to one copy: it is not safe for concurrent use.

func NewCloneMemo

func NewCloneMemo() *CloneMemo

NewCloneMemo returns an empty memo. Pass it to Release when the copy is done so it can be reused.

func (*CloneMemo) Load

func (c *CloneMemo) Load(src any) (any, bool)

Load returns the copy already made for the pointer src, if there is one.

Identity is the pointer's address together with its type: pointers of different types that share an address — a struct and its first field — do not collide.

func (*CloneMemo) Release

func (c *CloneMemo) Release()

Release returns c for reuse. The copies it recorded stay valid — only the bookkeeping is discarded — but it must not be called while a copy using c is still running.

func (*CloneMemo) Store

func (c *CloneMemo) Store(src, dst any)

Store records dst as the copy of the pointer src. It must be called before descending into src's fields: that is what lets a reference back to src, from anywhere below it, resolve to dst instead of starting the copy over.

type DiffMemo

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

DiffMemo tracks the pairs of values a generated Diff has visited, and turns repeat visits into alias operations.

A pair is diffed once, at the first path that reaches it — shared structure can be reachable by exponentially many paths, so diffing every route is not an option. Each later route that reaches an already-diffed, changed pair records one OpAlias operation instead: "make this path point at the same object as the first path". Applied in order, the aliases rebuild the sharing the new value has, whatever the target looked like before.

A memo belongs to one Diff call: it is not safe for concurrent use.

func NewDiffMemo

func NewDiffMemo() *DiffMemo

NewDiffMemo returns an empty memo. Pass it to Release when the diff is done so it can be reused.

func (*DiffMemo) AliasOperations

func (d *DiffMemo) AliasOperations() []engine.Operation

AliasOperations returns the alias operations recorded so far, in the order the routes were reached. Generated Diff appends them after its own operations; an alias shares the object its From path holds, so it lands correctly whether the operations before it mutated that object in place or replaced it.

func (*DiffMemo) Enter

func (d *DiffMemo) Enter(a, b any, path string) bool

Enter reports whether the pair (a, b), reached at path, is new.

True means the caller should diff the pair, then call Leave. False means the pair is already handled: if a completed visit found changes, Enter has recorded an alias operation for this path — reporting the changes again here would repeat them once per route, and there can be exponentially many routes. A pair still in progress is a cycle, and is left to the comparison already under way.

func (*DiffMemo) Leave

func (d *DiffMemo) Leave(a, b any, ops int)

Leave completes the visit Enter opened for (a, b). ops is the number of operations the pair's diff produced; the pair also counts as changed when aliases were recorded below it, since those are changes too — just ones that live in this memo rather than in the caller's patch.

func (*DiffMemo) Release

func (d *DiffMemo) Release()

Release returns d for reuse. It must not be called while a diff using d is still running. The operations AliasOperations returned stay valid: appending them copies the values.

type VisitSet

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

VisitSet records the pairs of values a recursive comparison has already started on, so that following a cycle stops when it repeats rather than running forever, and a value reachable by many routes is compared once instead of once per route.

Generated Equal methods create and thread a set when values of the type can reach the same value twice. Types where that cannot happen never allocate one.

A set belongs to one comparison: it is not safe for concurrent use.

func NewVisitSet

func NewVisitSet() *VisitSet

NewVisitSet returns an empty set. Pass it to Release when the comparison is done so it can be reused.

func (*VisitSet) Enter

func (v *VisitSet) Enter(a, b any) bool

Enter records the pair (a, b) and reports whether it is new. A false result means the pair has been reached before and the caller should treat the two as matching rather than descend again: once a pair has been compared the answer is settled — had it differed, the comparison would already have stopped — and for a pair still being compared further up a cycle, the two differ only if something else on the cycle differs, which that comparison will find.

func (*VisitSet) Release

func (v *VisitSet) Release()

Release returns v for reuse. It must not be called while a comparison using v is still running.

Jump to

Keyboard shortcuts

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