blob: b584dbef7f44bb6ebd46e0094ee3c5a381693015 [file] [log] [blame]
package collections
import (
"reflect"
"github.com/hashicorp/terraform/internal/command/jsonformat/computed"
"github.com/hashicorp/terraform/internal/plans"
"github.com/hashicorp/terraform/internal/plans/objchange"
)
type TransformIndices func(before, after int) computed.Diff
type ProcessIndices func(before, after int)
type IsObjType[Input any] func(input Input) bool
func TransformSlice[Input any](before, after []Input, process TransformIndices, isObjType IsObjType[Input]) ([]computed.Diff, plans.Action) {
current := plans.NoOp
if before != nil && after == nil {
current = plans.Delete
}
if before == nil && after != nil {
current = plans.Create
}
var elements []computed.Diff
ProcessSlice(before, after, func(before, after int) {
element := process(before, after)
elements = append(elements, element)
current = CompareActions(current, element.Action)
}, isObjType)
return elements, current
}
func ProcessSlice[Input any](before, after []Input, process ProcessIndices, isObjType IsObjType[Input]) {
lcs := objchange.LongestCommonSubsequence(before, after, func(before, after Input) bool {
return reflect.DeepEqual(before, after)
})
var beforeIx, afterIx, lcsIx int
for beforeIx < len(before) || afterIx < len(after) || lcsIx < len(lcs) {
// Step through all the before values until we hit the next item in the
// longest common subsequence. We are going to just say that all of
// these have been deleted.
for beforeIx < len(before) && (lcsIx >= len(lcs) || !reflect.DeepEqual(before[beforeIx], lcs[lcsIx])) {
isObjectDiff := isObjType(before[beforeIx]) && afterIx < len(after) && isObjType(after[afterIx]) && (lcsIx >= len(lcs) || !reflect.DeepEqual(after[afterIx], lcs[lcsIx]))
if isObjectDiff {
process(beforeIx, afterIx)
beforeIx++
afterIx++
continue
}
process(beforeIx, len(after))
beforeIx++
}
// Now, step through all the after values until hit the next item in the
// LCS. We are going to say that all of these have been created.
for afterIx < len(after) && (lcsIx >= len(lcs) || !reflect.DeepEqual(after[afterIx], lcs[lcsIx])) {
process(len(before), afterIx)
afterIx++
}
// Finally, add the item in common as unchanged.
if lcsIx < len(lcs) {
process(beforeIx, afterIx)
beforeIx++
afterIx++
lcsIx++
}
}
}