func (c *Comparison) IsSame() bool {
	return c.Removed.Empty() && c.Modified.Empty() && c.Added.Empty()
}
IsSame returns true if the comparison returned no changes (the two
compared objects are similar).
package typed
import (
	"fmt"
	"strings"
	"sync"
	"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
	"sigs.k8s.io/structured-merge-diff/v4/schema"
	"sigs.k8s.io/structured-merge-diff/v4/value"
)
func AsTyped(v value.Value, s *schema.Schema, typeRef schema.TypeRef) (*TypedValue, error) {
	tv := &TypedValue{
		value:   v,
		typeRef: typeRef,
		schema:  s,
	}
	if err := tv.Validate(); err != nil {
		return nil, err
	}
	return tv, nil
}
func AsTypedUnvalidated(v value.Value, s *schema.Schema, typeRef schema.TypeRef) *TypedValue {
	tv := &TypedValue{
		value:   v,
		typeRef: typeRef,
		schema:  s,
	}
	return tv
}
type TypedValue struct {
	value   value.Value
	typeRef schema.TypeRef
	schema  *schema.Schema
}
func (tv TypedValue) TypeRef() schema.TypeRef {
	return tv.typeRef
}
func (tv TypedValue) AsValue() value.Value {
	return tv.value
}
func (tv TypedValue) Schema() *schema.Schema {
	return tv.schema
}
func (tv TypedValue) Validate() error {
	w := tv.walker()
	defer w.finished()
	if errs := w.validate(nil); len(errs) != 0 {
		return errs
	}
	return nil
}
func (tv TypedValue) ToFieldSet() (*fieldpath.Set, error) {
	w := tv.toFieldSetWalker()
	defer w.finished()
	if errs := w.toFieldSet(); len(errs) != 0 {
		return nil, errs
	}
	return w.set, nil
}
func (tv TypedValue) Merge(pso *TypedValue) (*TypedValue, error) {
	return merge(&tv, pso, ruleKeepRHS, nil)
}
func (tv TypedValue) Compare(rhs *TypedValue) (c *Comparison, err error) {
	c = &Comparison{
		Removed:  fieldpath.NewSet(),
		Modified: fieldpath.NewSet(),
		Added:    fieldpath.NewSet(),
	}
	_, err = merge(&tv, rhs, func(w *mergingWalker) {
		if w.lhs == nil {
			c.Added.Insert(w.path)
		} else if w.rhs == nil {
			c.Removed.Insert(w.path)
		} else if !value.Equals(w.rhs, w.lhs) {
			c.Modified.Insert(w.path)
		}
	}, func(w *mergingWalker) {
		if w.lhs == nil {
			c.Added.Insert(w.path)
		} else if w.rhs == nil {
			c.Removed.Insert(w.path)
		}
	})
	if err != nil {
		return nil, err
	}
	return c, nil
}
func (tv TypedValue) RemoveItems(items *fieldpath.Set) *TypedValue {
	tv.value = removeItemsWithSchema(tv.value, items, tv.schema, tv.typeRef, false)
	return &tv
}
func (tv TypedValue) ExtractItems(items *fieldpath.Set) *TypedValue {
	tv.value = removeItemsWithSchema(tv.value, items, tv.schema, tv.typeRef, true)
	return &tv
}
func (tv TypedValue) NormalizeUnions(new *TypedValue) (*TypedValue, error) {
	var errs ValidationErrors
	var normalizeFn = func(w *mergingWalker) {
		if w.rhs != nil {
			v := w.rhs.Unstructured()
			w.out = &v
		}
		if err := normalizeUnions(w); err != nil {
			errs = append(errs, errorf(err.Error())...)
		}
	}
	out, mergeErrs := merge(&tv, new, func(w *mergingWalker) {}, normalizeFn)
	if mergeErrs != nil {
		errs = append(errs, mergeErrs.(ValidationErrors)...)
	}
	if len(errs) > 0 {
		return nil, errs
	}
	return out, nil
}
func (tv TypedValue) NormalizeUnionsApply(new *TypedValue) (*TypedValue, error) {
	var errs ValidationErrors
	var normalizeFn = func(w *mergingWalker) {
		if w.rhs != nil {
			v := w.rhs.Unstructured()
			w.out = &v
		}
		if err := normalizeUnionsApply(w); err != nil {
			errs = append(errs, errorf(err.Error())...)
		}
	}
	out, mergeErrs := merge(&tv, new, func(w *mergingWalker) {}, normalizeFn)
	if mergeErrs != nil {
		errs = append(errs, mergeErrs.(ValidationErrors)...)
	}
	if len(errs) > 0 {
		return nil, errs
	}
	return out, nil
}
func (tv TypedValue) Empty() *TypedValue {
	tv.value = value.NewValueInterface(nil)
	return &tv
}
var mwPool = sync.Pool{
	New: func() interface{} { return &mergingWalker{} },
}
func merge(lhs, rhs *TypedValue, rule, postRule mergeRule) (*TypedValue, error) {
	if lhs.schema != rhs.schema {
		return nil, errorf("expected objects with types from the same schema")
	}
	if !lhs.typeRef.Equals(&rhs.typeRef) {
		return nil, errorf("expected objects of the same type, but got %v and %v", lhs.typeRef, rhs.typeRef)
	}
	mw := mwPool.Get().(*mergingWalker)
	defer func() {
		mw.lhs = nil
		mw.rhs = nil
		mw.schema = nil
		mw.typeRef = schema.TypeRef{}
		mw.rule = nil
		mw.postItemHook = nil
		mw.out = nil
		mw.inLeaf = false
		mwPool.Put(mw)
	}()
	mw.lhs = lhs.value
	mw.rhs = rhs.value
	mw.schema = lhs.schema
	mw.typeRef = lhs.typeRef
	mw.rule = rule
	mw.postItemHook = postRule
	if mw.allocator == nil {
		mw.allocator = value.NewFreelistAllocator()
	}
	errs := mw.merge(nil)
	if len(errs) > 0 {
		return nil, errs
	}
	out := &TypedValue{
		schema:  lhs.schema,
		typeRef: lhs.typeRef,
	}
	if mw.out != nil {
		out.value = value.NewValueInterface(*mw.out)
	}
	return out, nil
}
type Comparison struct {
	Removed *fieldpath.Set
	Modified *fieldpath.Set
	Added *fieldpath.Set
}