| 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++ |
| } |
| } |
| } |