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  }