type Option … type applicableOption … type coreOption … type core … func (core) isCore() { … } type Options … func (opts Options) filter(s *state, t reflect.Type, vx, vy reflect.Value) (out applicableOption) { … } func (opts Options) apply(s *state, _, _ reflect.Value) { … } func (opts Options) String() string { … } // FilterPath returns a new [Option] where opt is only evaluated if filter f // returns true for the current [Path] in the value tree. // // This filter is called even if a slice element or map entry is missing and // provides an opportunity to ignore such cases. The filter function must be // symmetric such that the filter result is identical regardless of whether the // missing value is from x or y. // // The option passed in may be an [Ignore], [Transformer], [Comparer], [Options], or // a previously filtered [Option]. func FilterPath(f func(Path) bool, opt Option) Option { … } type pathFilter … func (f pathFilter) filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption { … } func (f pathFilter) String() string { … } // FilterValues returns a new [Option] where opt is only evaluated if filter f, // which is a function of the form "func(T, T) bool", returns true for the // current pair of values being compared. If either value is invalid or // the type of the values is not assignable to T, then this filter implicitly // returns false. // // The filter function must be // symmetric (i.e., agnostic to the order of the inputs) and // deterministic (i.e., produces the same result when given the same inputs). // If T is an interface, it is possible that f is called with two values with // different concrete types that both implement T. // // The option passed in may be an [Ignore], [Transformer], [Comparer], [Options], or // a previously filtered [Option]. func FilterValues(f interface{ … } type valuesFilter … func (f valuesFilter) filter(s *state, t reflect.Type, vx, vy reflect.Value) applicableOption { … } func (f valuesFilter) String() string { … } // Ignore is an [Option] that causes all comparisons to be ignored. // This value is intended to be combined with [FilterPath] or [FilterValues]. // It is an error to pass an unfiltered Ignore option to [Equal]. func Ignore() Option { … } type ignore … func (ignore) isFiltered() bool { … } func (ignore) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption { … } func (ignore) apply(s *state, _, _ reflect.Value) { … } func (ignore) String() string { … } type validator … func (validator) filter(_ *state, _ reflect.Type, vx, vy reflect.Value) applicableOption { … } func (validator) apply(s *state, vx, vy reflect.Value) { … } const identRx … var identsRx … // Transformer returns an [Option] that applies a transformation function that // converts values of a certain type into that of another. // // The transformer f must be a function "func(T) R" that converts values of // type T to those of type R and is implicitly filtered to input values // assignable to T. The transformer must not mutate T in any way. // // To help prevent some cases of infinite recursive cycles applying the // same transform to the output of itself (e.g., in the case where the // input and output types are the same), an implicit filter is added such that // a transformer is applicable only if that exact transformer is not already // in the tail of the [Path] since the last non-[Transform] step. // For situations where the implicit filter is still insufficient, // consider using [github.com/google/go-cmp/cmp/cmpopts.AcyclicTransformer], // which adds a filter to prevent the transformer from // being recursively applied upon itself. // // The name is a user provided label that is used as the [Transform.Name] in the // transformation [PathStep] (and eventually shown in the [Diff] output). // The name must be a valid identifier or qualified identifier in Go syntax. // If empty, an arbitrary name is used. func Transformer(name string, f interface{ … } type transformer … func (tr *transformer) isFiltered() bool { … } func (tr *transformer) filter(s *state, t reflect.Type, _, _ reflect.Value) applicableOption { … } func (tr *transformer) apply(s *state, vx, vy reflect.Value) { … } func (tr transformer) String() string { … } // Comparer returns an [Option] that determines whether two values are equal // to each other. // // The comparer f must be a function "func(T, T) bool" and is implicitly // filtered to input values assignable to T. If T is an interface, it is // possible that f is called with two values of different concrete types that // both implement T. // // The equality function must be: // - Symmetric: equal(x, y) == equal(y, x) // - Deterministic: equal(x, y) == equal(x, y) // - Pure: equal(x, y) does not modify x or y func Comparer(f interface{ … } type comparer … func (cm *comparer) isFiltered() bool { … } func (cm *comparer) filter(_ *state, t reflect.Type, _, _ reflect.Value) applicableOption { … } func (cm *comparer) apply(s *state, vx, vy reflect.Value) { … } func (cm comparer) String() string { … } // Exporter returns an [Option] that specifies whether [Equal] is allowed to // introspect into the unexported fields of certain struct types. // // Users of this option must understand that comparing on unexported fields // from external packages is not safe since changes in the internal // implementation of some external package may cause the result of [Equal] // to unexpectedly change. However, it may be valid to use this option on types // defined in an internal package where the semantic meaning of an unexported // field is in the control of the user. // // In many cases, a custom [Comparer] should be used instead that defines // equality as a function of the public API of a type rather than the underlying // unexported implementation. // // For example, the [reflect.Type] documentation defines equality to be determined // by the == operator on the interface (essentially performing a shallow pointer // comparison) and most attempts to compare *[regexp.Regexp] types are interested // in only checking that the regular expression strings are equal. // Both of these are accomplished using [Comparer] options: // // Comparer(func(x, y reflect.Type) bool { return x == y }) // Comparer(func(x, y *regexp.Regexp) bool { return x.String() == y.String() }) // // In other cases, the [github.com/google/go-cmp/cmp/cmpopts.IgnoreUnexported] // option can be used to ignore all unexported fields on specified struct types. func Exporter(f func(reflect.Type) bool) Option { … } type exporter … func (exporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption { … } // AllowUnexported returns an [Option] that allows [Equal] to forcibly introspect // unexported fields of the specified struct types. // // See [Exporter] for the proper use of this option. func AllowUnexported(types ...interface{ … } type Result … // Equal reports whether the node was determined to be equal or not. // As a special case, ignored nodes are considered equal. func (r Result) Equal() bool { … } // ByIgnore reports whether the node is equal because it was ignored. // This never reports true if [Result.Equal] reports false. func (r Result) ByIgnore() bool { … } // ByMethod reports whether the Equal method determined equality. func (r Result) ByMethod() bool { … } // ByFunc reports whether a [Comparer] function determined equality. func (r Result) ByFunc() bool { … } // ByCycle reports whether a reference cycle was detected. func (r Result) ByCycle() bool { … } type resultFlags … const _ … const reportEqual … const reportUnequal … const reportByIgnore … const reportByMethod … const reportByFunc … const reportByCycle … // Reporter is an [Option] that can be passed to [Equal]. When [Equal] traverses // the value trees, it calls PushStep as it descends into each node in the // tree and PopStep as it ascend out of the node. The leaves of the tree are // either compared (determined to be equal or not equal) or ignored and reported // as such by calling the Report method. func Reporter(r interface { … } type reporter … type reporterIface … func (reporter) filter(_ *state, _ reflect.Type, _, _ reflect.Value) applicableOption { … } // normalizeOption normalizes the input options such that all Options groups // are flattened and groups with a single element are reduced to that element. // Only coreOptions and Options containing coreOptions are allowed. func normalizeOption(src Option) Option { … } // flattenOptions copies all options in src to dst as a flat list. // Only coreOptions and Options containing coreOptions are allowed. func flattenOptions(dst, src Options) Options { … }