github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/command/jsonformat/collections/slice.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package collections 5 6 import ( 7 "reflect" 8 9 "github.com/terramate-io/tf/command/jsonformat/computed" 10 11 "github.com/terramate-io/tf/plans" 12 "github.com/terramate-io/tf/plans/objchange" 13 ) 14 15 type TransformIndices func(before, after int) computed.Diff 16 type ProcessIndices func(before, after int) 17 type IsObjType[Input any] func(input Input) bool 18 19 func TransformSlice[Input any](before, after []Input, process TransformIndices, isObjType IsObjType[Input]) ([]computed.Diff, plans.Action) { 20 current := plans.NoOp 21 if before != nil && after == nil { 22 current = plans.Delete 23 } 24 if before == nil && after != nil { 25 current = plans.Create 26 } 27 28 var elements []computed.Diff 29 ProcessSlice(before, after, func(before, after int) { 30 element := process(before, after) 31 elements = append(elements, element) 32 current = CompareActions(current, element.Action) 33 }, isObjType) 34 return elements, current 35 } 36 37 func ProcessSlice[Input any](before, after []Input, process ProcessIndices, isObjType IsObjType[Input]) { 38 lcs := objchange.LongestCommonSubsequence(before, after, func(before, after Input) bool { 39 return reflect.DeepEqual(before, after) 40 }) 41 42 var beforeIx, afterIx, lcsIx int 43 for beforeIx < len(before) || afterIx < len(after) || lcsIx < len(lcs) { 44 // Step through all the before values until we hit the next item in the 45 // longest common subsequence. We are going to just say that all of 46 // these have been deleted. 47 for beforeIx < len(before) && (lcsIx >= len(lcs) || !reflect.DeepEqual(before[beforeIx], lcs[lcsIx])) { 48 isObjectDiff := isObjType(before[beforeIx]) && afterIx < len(after) && isObjType(after[afterIx]) && (lcsIx >= len(lcs) || !reflect.DeepEqual(after[afterIx], lcs[lcsIx])) 49 if isObjectDiff { 50 process(beforeIx, afterIx) 51 beforeIx++ 52 afterIx++ 53 continue 54 } 55 56 process(beforeIx, len(after)) 57 beforeIx++ 58 } 59 60 // Now, step through all the after values until hit the next item in the 61 // LCS. We are going to say that all of these have been created. 62 for afterIx < len(after) && (lcsIx >= len(lcs) || !reflect.DeepEqual(after[afterIx], lcs[lcsIx])) { 63 process(len(before), afterIx) 64 afterIx++ 65 } 66 67 // Finally, add the item in common as unchanged. 68 if lcsIx < len(lcs) { 69 process(beforeIx, afterIx) 70 beforeIx++ 71 afterIx++ 72 lcsIx++ 73 } 74 } 75 }