func (s *SyncState) maybePruneModule(addr addrs.ModuleInstance) {
	if addr.IsRoot() {
		return
	}
	ms := s.state.Module(addr)
	if ms == nil {
		return
	}
	if ms.empty() {
		log.Printf("[TRACE] states.SyncState: pruning %s because it is empty", addr)
		s.state.RemoveModule(addr)
	}
}
maybePruneModule will remove a module from the state altogether if it is
empty, unless it's the root module which must always be present.

This helper method is not concurrency-safe on its own, so must only be
called while the caller is already holding the lock for writing.
package states
import (
	"log"
	"sync"
	"github.com/camptocamp/terraboard/internal/terraform/addrs"
	"github.com/zclconf/go-cty/cty"
)
type SyncState struct {
	state *State
	lock  sync.RWMutex
}
func (s *SyncState) Module(addr addrs.ModuleInstance) *Module {
	s.lock.RLock()
	ret := s.state.Module(addr).DeepCopy()
	s.lock.RUnlock()
	return ret
}
func (s *SyncState) ModuleOutputs(parentAddr addrs.ModuleInstance, module addrs.ModuleCall) []*OutputValue {
	s.lock.RLock()
	defer s.lock.RUnlock()
	var os []*OutputValue
	for _, o := range s.state.ModuleOutputs(parentAddr, module) {
		os = append(os, o.DeepCopy())
	}
	return os
}
func (s *SyncState) RemoveModule(addr addrs.ModuleInstance) {
	s.lock.Lock()
	defer s.lock.Unlock()
	s.state.RemoveModule(addr)
}
func (s *SyncState) OutputValue(addr addrs.AbsOutputValue) *OutputValue {
	s.lock.RLock()
	ret := s.state.OutputValue(addr).DeepCopy()
	s.lock.RUnlock()
	return ret
}
func (s *SyncState) SetOutputValue(addr addrs.AbsOutputValue, value cty.Value, sensitive bool) {
	s.lock.Lock()
	defer s.lock.Unlock()
	ms := s.state.EnsureModule(addr.Module)
	ms.SetOutputValue(addr.OutputValue.Name, value, sensitive)
}
func (s *SyncState) RemoveOutputValue(addr addrs.AbsOutputValue) {
	s.lock.Lock()
	defer s.lock.Unlock()
	ms := s.state.Module(addr.Module)
	if ms == nil {
		return
	}
	ms.RemoveOutputValue(addr.OutputValue.Name)
	s.maybePruneModule(addr.Module)
}
func (s *SyncState) LocalValue(addr addrs.AbsLocalValue) cty.Value {
	s.lock.RLock()
	ret := s.state.LocalValue(addr)
	s.lock.RUnlock()
	return ret
}
func (s *SyncState) SetLocalValue(addr addrs.AbsLocalValue, value cty.Value) {
	s.lock.Lock()
	defer s.lock.Unlock()
	ms := s.state.EnsureModule(addr.Module)
	ms.SetLocalValue(addr.LocalValue.Name, value)
}
func (s *SyncState) RemoveLocalValue(addr addrs.AbsLocalValue) {
	s.lock.Lock()
	defer s.lock.Unlock()
	ms := s.state.Module(addr.Module)
	if ms == nil {
		return
	}
	ms.RemoveLocalValue(addr.LocalValue.Name)
	s.maybePruneModule(addr.Module)
}
func (s *SyncState) Resource(addr addrs.AbsResource) *Resource {
	s.lock.RLock()
	ret := s.state.Resource(addr).DeepCopy()
	s.lock.RUnlock()
	return ret
}
func (s *SyncState) ResourceInstance(addr addrs.AbsResourceInstance) *ResourceInstance {
	s.lock.RLock()
	ret := s.state.ResourceInstance(addr).DeepCopy()
	s.lock.RUnlock()
	return ret
}
func (s *SyncState) ResourceInstanceObject(addr addrs.AbsResourceInstance, gen Generation) *ResourceInstanceObjectSrc {
	s.lock.RLock()
	defer s.lock.RUnlock()
	inst := s.state.ResourceInstance(addr)
	if inst == nil {
		return nil
	}
	return inst.GetGeneration(gen).DeepCopy()
}
func (s *SyncState) SetResourceProvider(addr addrs.AbsResource, provider addrs.AbsProviderConfig) {
	s.lock.Lock()
	defer s.lock.Unlock()
	ms := s.state.EnsureModule(addr.Module)
	ms.SetResourceProvider(addr.Resource, provider)
}
func (s *SyncState) RemoveResource(addr addrs.AbsResource) {
	s.lock.Lock()
	defer s.lock.Unlock()
	ms := s.state.EnsureModule(addr.Module)
	ms.RemoveResource(addr.Resource)
	s.maybePruneModule(addr.Module)
}
func (s *SyncState) RemoveResourceIfEmpty(addr addrs.AbsResource) bool {
	s.lock.Lock()
	defer s.lock.Unlock()
	ms := s.state.Module(addr.Module)
	if ms == nil {
		return true  
	}
	rs := ms.Resource(addr.Resource)
	if rs == nil {
		return true  
	}
	if len(rs.Instances) != 0 {
		return false
	}
	ms.RemoveResource(addr.Resource)
	s.maybePruneModule(addr.Module)
	return true
}
func (s *SyncState) MaybeFixUpResourceInstanceAddressForCount(addr addrs.ConfigResource, countEnabled bool) bool {
	s.lock.Lock()
	defer s.lock.Unlock()
	modules := s.state.ModuleInstances(addr.Module)
	if len(modules) == 0 {
		return false
	}
	changed := false
	for _, ms := range modules {
		relAddr := addr.Resource
		rs := ms.Resource(relAddr)
		if rs == nil {
			continue
		}
		huntKey := addrs.NoKey
		replaceKey := addrs.InstanceKey(addrs.IntKey(0))
		if !countEnabled {
			huntKey, replaceKey = replaceKey, huntKey
		}
		is, exists := rs.Instances[huntKey]
		if !exists {
			continue
		}
		if _, exists := rs.Instances[replaceKey]; exists {
			continue
		}
		rs.Instances[replaceKey] = is
		delete(rs.Instances, huntKey)
		changed = true
	}
	return changed
}
func (s *SyncState) SetResourceInstanceCurrent(addr addrs.AbsResourceInstance, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
	s.lock.Lock()
	defer s.lock.Unlock()
	ms := s.state.EnsureModule(addr.Module)
	ms.SetResourceInstanceCurrent(addr.Resource, obj.DeepCopy(), provider)
	s.maybePruneModule(addr.Module)
}
func (s *SyncState) SetResourceInstanceDeposed(addr addrs.AbsResourceInstance, key DeposedKey, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
	s.lock.Lock()
	defer s.lock.Unlock()
	ms := s.state.EnsureModule(addr.Module)
	ms.SetResourceInstanceDeposed(addr.Resource, key, obj.DeepCopy(), provider)
	s.maybePruneModule(addr.Module)
}
func (s *SyncState) DeposeResourceInstanceObject(addr addrs.AbsResourceInstance) DeposedKey {
	s.lock.Lock()
	defer s.lock.Unlock()
	ms := s.state.Module(addr.Module)
	if ms == nil {
		return NotDeposed
	}
	return ms.deposeResourceInstanceObject(addr.Resource, NotDeposed)
}
func (s *SyncState) DeposeResourceInstanceObjectForceKey(addr addrs.AbsResourceInstance, forcedKey DeposedKey) {
	s.lock.Lock()
	defer s.lock.Unlock()
	if forcedKey == NotDeposed {
		panic("DeposeResourceInstanceObjectForceKey called without forced key")
	}
	ms := s.state.Module(addr.Module)
	if ms == nil {
		return  
	}
	ms.deposeResourceInstanceObject(addr.Resource, forcedKey)
}
func (s *SyncState) ForgetResourceInstanceAll(addr addrs.AbsResourceInstance) {
	s.lock.Lock()
	defer s.lock.Unlock()
	ms := s.state.Module(addr.Module)
	if ms == nil {
		return
	}
	ms.ForgetResourceInstanceAll(addr.Resource)
	s.maybePruneModule(addr.Module)
}
func (s *SyncState) ForgetResourceInstanceDeposed(addr addrs.AbsResourceInstance, key DeposedKey) {
	s.lock.Lock()
	defer s.lock.Unlock()
	ms := s.state.Module(addr.Module)
	if ms == nil {
		return
	}
	ms.ForgetResourceInstanceDeposed(addr.Resource, key)
	s.maybePruneModule(addr.Module)
}
func (s *SyncState) MaybeRestoreResourceInstanceDeposed(addr addrs.AbsResourceInstance, key DeposedKey) bool {
	s.lock.Lock()
	defer s.lock.Unlock()
	if key == NotDeposed {
		panic("MaybeRestoreResourceInstanceDeposed called without DeposedKey")
	}
	ms := s.state.Module(addr.Module)
	if ms == nil {
		return false
	}
	return ms.maybeRestoreResourceInstanceDeposed(addr.Resource, key)
}
func (s *SyncState) RemovePlannedResourceInstanceObjects() {
	s.lock.Lock()
	defer s.lock.Unlock()
	for _, ms := range s.state.Modules {
		moduleAddr := ms.Addr
		for _, rs := range ms.Resources {
			resAddr := rs.Addr.Resource
			for ik, is := range rs.Instances {
				instAddr := resAddr.Instance(ik)
				if is.Current != nil && is.Current.Status == ObjectPlanned {
					ms.SetResourceInstanceCurrent(instAddr, nil, rs.ProviderConfig)
				}
				for dk, obj := range is.Deposed {
					if obj.Status == ObjectPlanned {
						ms.ForgetResourceInstanceDeposed(instAddr, dk)
					}
				}
			}
		}
		s.maybePruneModule(moduleAddr)
	}
}
func (s *SyncState) Lock() *State {
	s.lock.Lock()
	return s.state
}
func (s *SyncState) Unlock() {
	s.lock.Unlock()
}