blob: 383e5729cbc75de6b1a13312114cadcf60e8d5d5 [file] [log] [blame] [edit]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package stackaddrs
import (
"reflect"
"github.com/hashicorp/terraform/internal/collections"
)
// Referenceable is a type set containing all address types that can be
// the target of an expression-based reference within a particular stack.
type Referenceable interface {
referenceableSigil()
String() string
}
var _ Referenceable = Component{}
var _ Referenceable = StackCall{}
var _ Referenceable = InputVariable{}
var _ Referenceable = LocalValue{}
var _ Referenceable = ProviderConfigRef{}
var _ Referenceable = TestOnlyGlobal{}
var _ Referenceable = ContextualRef(0)
// ReferenceableUniqueKey returns a unique key for a dynamically-typed
// referenceable address.
//
// Since the type of the target isn't statically known, the resulting unique
// key is not comparable with unique keys of the specific static types
// that implement [Referenceable].
func ReferenceableUniqueKey(addr Referenceable) collections.UniqueKey[Referenceable] {
// NOTE: This assumes that all distinct referenceable addresses have
// distinct and unique string representations.
return referenceableUniqueKey{
ty: reflect.TypeOf(addr),
str: addr.String(),
}
}
type referenceableUniqueKey struct {
ty reflect.Type
str string
}
// IsUniqueKey implements collections.UniqueKey.
func (referenceableUniqueKey) IsUniqueKey(Referenceable) {}
type ContextualRef rune
const EachValue = ContextualRef('v')
const EachKey = ContextualRef('k')
const CountIndex = ContextualRef('i')
const Self = ContextualRef('s')
const TerraformApplying = ContextualRef('a')
// String implements Referenceable.
func (e ContextualRef) String() string {
switch e {
case EachKey:
return "each.key"
case EachValue:
return "each.value"
case CountIndex:
return "count.index"
case Self:
return "self"
case TerraformApplying:
return "terraform.applying"
default:
// The four constants in this package are the only valid values of this type
panic("invalid ContextualRef instance")
}
}
// referenceableSigil implements Referenceable.
func (e ContextualRef) referenceableSigil() {}
// AbsReferenceable is a [Referenceable] combined with the stack it would
// be resolved in.
//
// This type can be used only for [Referenceable] types that have stack-wide
// scope. It's not appropriate for referenceable objects with more specific
// scope, such as [ContextualRef], since describing those would require
// information about which specific block they are to be resolved within.
type AbsReferenceable struct {
Stack StackInstance
Item Referenceable
}
func (r AbsReferenceable) UniqueKey() collections.UniqueKey[AbsReferenceable] {
return absReferenceableKey{
stackKey: r.Stack.UniqueKey(),
itemKey: ReferenceableUniqueKey(r.Item),
}
}
type absReferenceableKey struct {
stackKey collections.UniqueKey[StackInstance]
itemKey collections.UniqueKey[Referenceable]
}
// IsUniqueKey implements collections.UniqueKey.
func (absReferenceableKey) IsUniqueKey(AbsReferenceable) {
panic("unimplemented")
}