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 ¶
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 ¶
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
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 ¶
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 ¶
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.
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 ¶
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 ¶
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 ¶
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.
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 ¶
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.