// Copyright 2017, The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cmp

import (
	
	
	
	
	

	
)

// Path is a list of PathSteps describing the sequence of operations to get
// from some root type to the current position in the value tree.
// The first Path element is always an operation-less PathStep that exists
// simply to identify the initial type.
//
// When traversing structs with embedded structs, the embedded struct will
// always be accessed as a field before traversing the fields of the
// embedded struct themselves. That is, an exported field from the
// embedded struct will never be accessed directly from the parent struct.
type Path []PathStep

// PathStep is a union-type for specific operations to traverse
// a value's tree structure. Users of this package never need to implement
// these types as values of this type will be returned by this package.
//
// Implementations of this interface are
// StructField, SliceIndex, MapIndex, Indirect, TypeAssertion, and Transform.
type PathStep interface {
	String() string

	// Type is the resulting type after performing the path step.
	Type() reflect.Type

	// Values is the resulting values after performing the path step.
	// The type of each valid value is guaranteed to be identical to Type.
	//
	// In some cases, one or both may be invalid or have restrictions:
	//   - For StructField, both are not interface-able if the current field
	//     is unexported and the struct type is not explicitly permitted by
	//     an Exporter to traverse unexported fields.
	//   - For SliceIndex, one may be invalid if an element is missing from
	//     either the x or y slice.
	//   - For MapIndex, one may be invalid if an entry is missing from
	//     either the x or y map.
	//
	// The provided values must not be mutated.
	Values() (vx, vy reflect.Value)
}

var (
	_ PathStep = StructField{}
	_ PathStep = SliceIndex{}
	_ PathStep = MapIndex{}
	_ PathStep = Indirect{}
	_ PathStep = TypeAssertion{}
	_ PathStep = Transform{}
)

func ( *Path) ( PathStep) {
	* = append(*, )
}

func ( *Path) () {
	* = (*)[:len(*)-1]
}

// Last returns the last PathStep in the Path.
// If the path is empty, this returns a non-nil PathStep that reports a nil Type.
func ( Path) () PathStep {
	return .Index(-1)
}

// Index returns the ith step in the Path and supports negative indexing.
// A negative index starts counting from the tail of the Path such that -1
// refers to the last step, -2 refers to the second-to-last step, and so on.
// If index is invalid, this returns a non-nil PathStep that reports a nil Type.
func ( Path) ( int) PathStep {
	if  < 0 {
		 = len() + 
	}
	if  < 0 ||  >= len() {
		return pathStep{}
	}
	return []
}

// String returns the simplified path to a node.
// The simplified path only contains struct field accesses.
//
// For example:
//
//	MyMap.MySlices.MyField
func ( Path) () string {
	var  []string
	for ,  := range  {
		if ,  := .(StructField);  {
			 = append(, .String())
		}
	}
	return strings.TrimPrefix(strings.Join(, ""), ".")
}

// GoString returns the path to a specific node using Go syntax.
//
// For example:
//
//	(*root.MyMap["key"].(*mypkg.MyStruct).MySlices)[2][3].MyField
func ( Path) () string {
	var ,  []string
	var  int
	for ,  := range  {
		var  PathStep
		if +1 < len() {
			 = [+1]
		}
		switch s := .(type) {
		case Indirect:
			++
			,  := "(", ")"
			switch .(type) {
			case Indirect:
				continue // Next step is indirection, so let them batch up
			case StructField:
				-- // Automatic indirection on struct fields
			case nil:
				,  = "", "" // Last step; no need for parenthesis
			}
			if  > 0 {
				 = append(, +strings.Repeat("*", ))
				 = append(, )
			}
			 = 0
			continue
		case Transform:
			 = append(, .trans.name+"(")
			 = append(, ")")
			continue
		}
		 = append(, .String())
	}
	for ,  := 0, len()-1;  < ; ,  = +1, -1 {
		[], [] = [], []
	}
	return strings.Join(, "") + strings.Join(, "")
}

type pathStep struct {
	typ    reflect.Type
	vx, vy reflect.Value
}

func ( pathStep) () reflect.Type             { return .typ }
func ( pathStep) () (,  reflect.Value) { return .vx, .vy }
func ( pathStep) () string {
	if .typ == nil {
		return "<nil>"
	}
	 := value.TypeString(.typ, false)
	if  == "" || strings.ContainsAny(, "{}\n") {
		return "root" // Type too simple or complex to print
	}
	return fmt.Sprintf("{%s}", )
}

// StructField represents a struct field access on a field called Name.
type StructField struct{ *structField }
type structField struct {
	pathStep
	name string
	idx  int

	// These fields are used for forcibly accessing an unexported field.
	// pvx, pvy, and field are only valid if unexported is true.
	unexported bool
	mayForce   bool                // Forcibly allow visibility
	paddr      bool                // Was parent addressable?
	pvx, pvy   reflect.Value       // Parent values (always addressable)
	field      reflect.StructField // Field information
}

func ( StructField) () reflect.Type { return .typ }
func ( StructField) () (,  reflect.Value) {
	if !.unexported {
		return .vx, .vy // CanInterface reports true
	}

	// Forcibly obtain read-write access to an unexported struct field.
	if .mayForce {
		 = retrieveUnexportedField(.pvx, .field, .paddr)
		 = retrieveUnexportedField(.pvy, .field, .paddr)
		return ,  // CanInterface reports true
	}
	return .vx, .vy // CanInterface reports false
}
func ( StructField) () string { return fmt.Sprintf(".%s", .name) }

// Name is the field name.
func ( StructField) () string { return .name }

// Index is the index of the field in the parent struct type.
// See reflect.Type.Field.
func ( StructField) () int { return .idx }

// SliceIndex is an index operation on a slice or array at some index Key.
type SliceIndex struct{ *sliceIndex }
type sliceIndex struct {
	pathStep
	xkey, ykey int
	isSlice    bool // False for reflect.Array
}

func ( SliceIndex) () reflect.Type             { return .typ }
func ( SliceIndex) () (,  reflect.Value) { return .vx, .vy }
func ( SliceIndex) () string {
	switch {
	case .xkey == .ykey:
		return fmt.Sprintf("[%d]", .xkey)
	case .ykey == -1:
		// [5->?] means "I don't know where X[5] went"
		return fmt.Sprintf("[%d->?]", .xkey)
	case .xkey == -1:
		// [?->3] means "I don't know where Y[3] came from"
		return fmt.Sprintf("[?->%d]", .ykey)
	default:
		// [5->3] means "X[5] moved to Y[3]"
		return fmt.Sprintf("[%d->%d]", .xkey, .ykey)
	}
}

// Key is the index key; it may return -1 if in a split state
func ( SliceIndex) () int {
	if .xkey != .ykey {
		return -1
	}
	return .xkey
}

// SplitKeys are the indexes for indexing into slices in the
// x and y values, respectively. These indexes may differ due to the
// insertion or removal of an element in one of the slices, causing
// all of the indexes to be shifted. If an index is -1, then that
// indicates that the element does not exist in the associated slice.
//
// Key is guaranteed to return -1 if and only if the indexes returned
// by SplitKeys are not the same. SplitKeys will never return -1 for
// both indexes.
func ( SliceIndex) () (,  int) { return .xkey, .ykey }

// MapIndex is an index operation on a map at some index Key.
type MapIndex struct{ *mapIndex }
type mapIndex struct {
	pathStep
	key reflect.Value
}

func ( MapIndex) () reflect.Type             { return .typ }
func ( MapIndex) () (,  reflect.Value) { return .vx, .vy }
func ( MapIndex) () string                 { return fmt.Sprintf("[%#v]", .key) }

// Key is the value of the map key.
func ( MapIndex) () reflect.Value { return .key }

// Indirect represents pointer indirection on the parent type.
type Indirect struct{ *indirect }
type indirect struct {
	pathStep
}

func ( Indirect) () reflect.Type             { return .typ }
func ( Indirect) () (,  reflect.Value) { return .vx, .vy }
func ( Indirect) () string                 { return "*" }

// TypeAssertion represents a type assertion on an interface.
type TypeAssertion struct{ *typeAssertion }
type typeAssertion struct {
	pathStep
}

func ( TypeAssertion) () reflect.Type             { return .typ }
func ( TypeAssertion) () (,  reflect.Value) { return .vx, .vy }
func ( TypeAssertion) () string                 { return fmt.Sprintf(".(%v)", value.TypeString(.typ, false)) }

// Transform is a transformation from the parent type to the current type.
type Transform struct{ *transform }
type transform struct {
	pathStep
	trans *transformer
}

func ( Transform) () reflect.Type             { return .typ }
func ( Transform) () (,  reflect.Value) { return .vx, .vy }
func ( Transform) () string                 { return fmt.Sprintf("%s()", .trans.name) }

// Name is the name of the Transformer.
func ( Transform) () string { return .trans.name }

// Func is the function pointer to the transformer function.
func ( Transform) () reflect.Value { return .trans.fnc }

// Option returns the originally constructed Transformer option.
// The == operator can be used to detect the exact option used.
func ( Transform) () Option { return .trans }

// pointerPath represents a dual-stack of pointers encountered when
// recursively traversing the x and y values. This data structure supports
// detection of cycles and determining whether the cycles are equal.
// In Go, cycles can occur via pointers, slices, and maps.
//
// The pointerPath uses a map to represent a stack; where descension into a
// pointer pushes the address onto the stack, and ascension from a pointer
// pops the address from the stack. Thus, when traversing into a pointer from
// reflect.Ptr, reflect.Slice element, or reflect.Map, we can detect cycles
// by checking whether the pointer has already been visited. The cycle detection
// uses a separate stack for the x and y values.
//
// If a cycle is detected we need to determine whether the two pointers
// should be considered equal. The definition of equality chosen by Equal
// requires two graphs to have the same structure. To determine this, both the
// x and y values must have a cycle where the previous pointers were also
// encountered together as a pair.
//
// Semantically, this is equivalent to augmenting Indirect, SliceIndex, and
// MapIndex with pointer information for the x and y values.
// Suppose px and py are two pointers to compare, we then search the
// Path for whether px was ever encountered in the Path history of x, and
// similarly so with py. If either side has a cycle, the comparison is only
// equal if both px and py have a cycle resulting from the same PathStep.
//
// Using a map as a stack is more performant as we can perform cycle detection
// in O(1) instead of O(N) where N is len(Path).
type pointerPath struct {
	// mx is keyed by x pointers, where the value is the associated y pointer.
	mx map[value.Pointer]value.Pointer
	// my is keyed by y pointers, where the value is the associated x pointer.
	my map[value.Pointer]value.Pointer
}

func ( *pointerPath) () {
	.mx = make(map[value.Pointer]value.Pointer)
	.my = make(map[value.Pointer]value.Pointer)
}

// Push indicates intent to descend into pointers vx and vy where
// visited reports whether either has been seen before. If visited before,
// equal reports whether both pointers were encountered together.
// Pop must be called if and only if the pointers were never visited.
//
// The pointers vx and vy must be a reflect.Ptr, reflect.Slice, or reflect.Map
// and be non-nil.
func ( pointerPath) (,  reflect.Value) (,  bool) {
	 := value.PointerOf()
	 := value.PointerOf()
	,  := .mx[]
	,  := .my[]
	if  ||  {
		 = .mx[] ==  && .my[] ==  // Pointers paired together
		return , true
	}
	.mx[] = 
	.my[] = 
	return false, false
}

// Pop ascends from pointers vx and vy.
func ( pointerPath) (,  reflect.Value) {
	delete(.mx, value.PointerOf())
	delete(.my, value.PointerOf())
}

// isExported reports whether the identifier is exported.
func ( string) bool {
	,  := utf8.DecodeRuneInString()
	return unicode.IsUpper()
}