github.com/opentofu/opentofu@v1.7.1/internal/command/jsonformat/structured/slice.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package structured 7 8 import ( 9 "github.com/opentofu/opentofu/internal/command/jsonformat/structured/attribute_path" 10 ) 11 12 // ChangeSlice is a Change that represents a Tuple, Set, or List type, and has 13 // converted the relevant interfaces into slices for easier access. 14 type ChangeSlice struct { 15 // Before contains the value before the proposed change. 16 Before []interface{} 17 18 // After contains the value after the proposed change. 19 After []interface{} 20 21 // Unknown contains the unknown status of any elements of this list/set. 22 Unknown []interface{} 23 24 // BeforeSensitive contains the before sensitive status of any elements of 25 //this list/set. 26 BeforeSensitive []interface{} 27 28 // AfterSensitive contains the after sensitive status of any elements of 29 //this list/set. 30 AfterSensitive []interface{} 31 32 // ReplacePaths matches the same attributes in Change exactly. 33 ReplacePaths attribute_path.Matcher 34 35 // RelevantAttributes matches the same attributes in Change exactly. 36 RelevantAttributes attribute_path.Matcher 37 } 38 39 // AsSlice converts the Change into a slice representation by converting the 40 // internal Before, After, Unknown, BeforeSensitive, and AfterSensitive data 41 // structures into generic slices. 42 func (change Change) AsSlice() ChangeSlice { 43 return ChangeSlice{ 44 Before: genericToSlice(change.Before), 45 After: genericToSlice(change.After), 46 Unknown: genericToSlice(change.Unknown), 47 BeforeSensitive: genericToSlice(change.BeforeSensitive), 48 AfterSensitive: genericToSlice(change.AfterSensitive), 49 ReplacePaths: change.ReplacePaths, 50 RelevantAttributes: change.RelevantAttributes, 51 } 52 } 53 54 // GetChild safely packages up a Change object for the given child, handling 55 // all the cases where the data might be null or a static boolean. 56 func (s ChangeSlice) GetChild(beforeIx, afterIx int) Change { 57 before, beforeExplicit := getFromGenericSlice(s.Before, beforeIx) 58 after, afterExplicit := getFromGenericSlice(s.After, afterIx) 59 unknown, _ := getFromGenericSlice(s.Unknown, afterIx) 60 beforeSensitive, _ := getFromGenericSlice(s.BeforeSensitive, beforeIx) 61 afterSensitive, _ := getFromGenericSlice(s.AfterSensitive, afterIx) 62 63 mostRelevantIx := beforeIx 64 if beforeIx < 0 || beforeIx >= len(s.Before) { 65 mostRelevantIx = afterIx 66 } 67 68 return Change{ 69 BeforeExplicit: beforeExplicit, 70 AfterExplicit: afterExplicit, 71 Before: before, 72 After: after, 73 Unknown: unknown, 74 BeforeSensitive: beforeSensitive, 75 AfterSensitive: afterSensitive, 76 ReplacePaths: s.ReplacePaths.GetChildWithIndex(mostRelevantIx), 77 RelevantAttributes: s.RelevantAttributes.GetChildWithIndex(mostRelevantIx), 78 } 79 } 80 81 func getFromGenericSlice(generic []interface{}, ix int) (interface{}, bool) { 82 if generic == nil { 83 return nil, false 84 } 85 if ix < 0 || ix >= len(generic) { 86 return nil, false 87 } 88 return generic[ix], true 89 } 90 91 func genericToSlice(generic interface{}) []interface{} { 92 if concrete, ok := generic.([]interface{}); ok { 93 return concrete 94 } 95 return nil 96 }