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  }