github.com/eliastor/durgaform@v0.0.0-20220816172711-d0ab2d17673e/internal/addrs/module.go (about) 1 package addrs 2 3 import ( 4 "strings" 5 ) 6 7 // Module is an address for a module call within configuration. This is 8 // the static counterpart of ModuleInstance, representing a traversal through 9 // the static module call tree in configuration and does not take into account 10 // the potentially-multiple instances of a module that might be created by 11 // "count" and "for_each" arguments within those calls. 12 // 13 // This type should be used only in very specialized cases when working with 14 // the static module call tree. Type ModuleInstance is appropriate in more cases. 15 // 16 // Although Module is a slice, it should be treated as immutable after creation. 17 type Module []string 18 19 // RootModule is the module address representing the root of the static module 20 // call tree, which is also the zero value of Module. 21 // 22 // Note that this is not the root of the dynamic module tree, which is instead 23 // represented by RootModuleInstance. 24 var RootModule Module 25 26 // IsRoot returns true if the receiver is the address of the root module, 27 // or false otherwise. 28 func (m Module) IsRoot() bool { 29 return len(m) == 0 30 } 31 32 func (m Module) String() string { 33 if len(m) == 0 { 34 return "" 35 } 36 // Calculate necessary space. 37 l := 0 38 for _, step := range m { 39 l += len(step) 40 } 41 buf := strings.Builder{} 42 // 8 is len(".module.") which separates entries. 43 buf.Grow(l + len(m)*8) 44 sep := "" 45 for _, step := range m { 46 buf.WriteString(sep) 47 buf.WriteString("module.") 48 buf.WriteString(step) 49 sep = "." 50 } 51 return buf.String() 52 } 53 54 func (m Module) Equal(other Module) bool { 55 if len(m) != len(other) { 56 return false 57 } 58 for i := range m { 59 if m[i] != other[i] { 60 return false 61 } 62 } 63 return true 64 } 65 66 func (m Module) targetableSigil() { 67 // Module is targetable 68 } 69 70 // TargetContains implements Targetable for Module by returning true if the given other 71 // address either matches the receiver, is a sub-module-instance of the 72 // receiver, or is a targetable absolute address within a module that 73 // is contained within the receiver. 74 func (m Module) TargetContains(other Targetable) bool { 75 switch to := other.(type) { 76 77 case Module: 78 if len(to) < len(m) { 79 // Can't be contained if the path is shorter 80 return false 81 } 82 // Other is contained if its steps match for the length of our own path. 83 for i, ourStep := range m { 84 otherStep := to[i] 85 if ourStep != otherStep { 86 return false 87 } 88 } 89 // If we fall out here then the prefixed matched, so it's contained. 90 return true 91 92 case ModuleInstance: 93 return m.TargetContains(to.Module()) 94 95 case ConfigResource: 96 return m.TargetContains(to.Module) 97 98 case AbsResource: 99 return m.TargetContains(to.Module) 100 101 case AbsResourceInstance: 102 return m.TargetContains(to.Module) 103 104 default: 105 return false 106 } 107 } 108 109 func (m Module) AddrType() TargetableAddrType { 110 return ModuleAddrType 111 } 112 113 // Child returns the address of a child call in the receiver, identified by the 114 // given name. 115 func (m Module) Child(name string) Module { 116 ret := make(Module, 0, len(m)+1) 117 ret = append(ret, m...) 118 return append(ret, name) 119 } 120 121 // Parent returns the address of the parent module of the receiver, or the 122 // receiver itself if there is no parent (if it's the root module address). 123 func (m Module) Parent() Module { 124 if len(m) == 0 { 125 return m 126 } 127 return m[:len(m)-1] 128 } 129 130 // Call returns the module call address that corresponds to the given module 131 // instance, along with the address of the module that contains it. 132 // 133 // There is no call for the root module, so this method will panic if called 134 // on the root module address. 135 // 136 // In practice, this just turns the last element of the receiver into a 137 // ModuleCall and then returns a slice of the receiever that excludes that 138 // last part. This is just a convenience for situations where a call address 139 // is required, such as when dealing with *Reference and Referencable values. 140 func (m Module) Call() (Module, ModuleCall) { 141 if len(m) == 0 { 142 panic("cannot produce ModuleCall for root module") 143 } 144 145 caller, callName := m[:len(m)-1], m[len(m)-1] 146 return caller, ModuleCall{ 147 Name: callName, 148 } 149 } 150 151 // Ancestors returns a slice containing the receiver and all of its ancestor 152 // modules, all the way up to (and including) the root module. The result is 153 // ordered by depth, with the root module always first. 154 // 155 // Since the result always includes the root module, a caller may choose to 156 // ignore it by slicing the result with [1:]. 157 func (m Module) Ancestors() []Module { 158 ret := make([]Module, 0, len(m)+1) 159 for i := 0; i <= len(m); i++ { 160 ret = append(ret, m[:i]) 161 } 162 return ret 163 } 164 165 func (m Module) configMoveableSigil() { 166 // ModuleInstance is moveable 167 }