mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 01:53:42 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			195 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package cty
 | 
						|
 | 
						|
import (
 | 
						|
	"sort"
 | 
						|
 | 
						|
	"github.com/zclconf/go-cty/cty/set"
 | 
						|
)
 | 
						|
 | 
						|
// ElementIterator is the interface type returned by Value.ElementIterator to
 | 
						|
// allow the caller to iterate over elements of a collection-typed value.
 | 
						|
//
 | 
						|
// Its usage pattern is as follows:
 | 
						|
//
 | 
						|
//     it := val.ElementIterator()
 | 
						|
//     for it.Next() {
 | 
						|
//         key, val := it.Element()
 | 
						|
//         // ...
 | 
						|
//     }
 | 
						|
type ElementIterator interface {
 | 
						|
	Next() bool
 | 
						|
	Element() (key Value, value Value)
 | 
						|
}
 | 
						|
 | 
						|
func canElementIterator(val Value) bool {
 | 
						|
	switch {
 | 
						|
	case val.IsMarked():
 | 
						|
		return false
 | 
						|
	case val.ty.IsListType():
 | 
						|
		return true
 | 
						|
	case val.ty.IsMapType():
 | 
						|
		return true
 | 
						|
	case val.ty.IsSetType():
 | 
						|
		return true
 | 
						|
	case val.ty.IsTupleType():
 | 
						|
		return true
 | 
						|
	case val.ty.IsObjectType():
 | 
						|
		return true
 | 
						|
	default:
 | 
						|
		return false
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func elementIterator(val Value) ElementIterator {
 | 
						|
	val.assertUnmarked()
 | 
						|
	switch {
 | 
						|
	case val.ty.IsListType():
 | 
						|
		return &listElementIterator{
 | 
						|
			ety:  val.ty.ElementType(),
 | 
						|
			vals: val.v.([]interface{}),
 | 
						|
			idx:  -1,
 | 
						|
		}
 | 
						|
	case val.ty.IsMapType():
 | 
						|
		// We iterate the keys in a predictable lexicographical order so
 | 
						|
		// that results will always be stable given the same input map.
 | 
						|
		rawMap := val.v.(map[string]interface{})
 | 
						|
		keys := make([]string, 0, len(rawMap))
 | 
						|
		for key := range rawMap {
 | 
						|
			keys = append(keys, key)
 | 
						|
		}
 | 
						|
		sort.Strings(keys)
 | 
						|
 | 
						|
		return &mapElementIterator{
 | 
						|
			ety:  val.ty.ElementType(),
 | 
						|
			vals: rawMap,
 | 
						|
			keys: keys,
 | 
						|
			idx:  -1,
 | 
						|
		}
 | 
						|
	case val.ty.IsSetType():
 | 
						|
		rawSet := val.v.(set.Set)
 | 
						|
		return &setElementIterator{
 | 
						|
			ety:   val.ty.ElementType(),
 | 
						|
			setIt: rawSet.Iterator(),
 | 
						|
		}
 | 
						|
	case val.ty.IsTupleType():
 | 
						|
		return &tupleElementIterator{
 | 
						|
			etys: val.ty.TupleElementTypes(),
 | 
						|
			vals: val.v.([]interface{}),
 | 
						|
			idx:  -1,
 | 
						|
		}
 | 
						|
	case val.ty.IsObjectType():
 | 
						|
		// We iterate the keys in a predictable lexicographical order so
 | 
						|
		// that results will always be stable given the same object type.
 | 
						|
		atys := val.ty.AttributeTypes()
 | 
						|
		keys := make([]string, 0, len(atys))
 | 
						|
		for key := range atys {
 | 
						|
			keys = append(keys, key)
 | 
						|
		}
 | 
						|
		sort.Strings(keys)
 | 
						|
 | 
						|
		return &objectElementIterator{
 | 
						|
			atys:      atys,
 | 
						|
			vals:      val.v.(map[string]interface{}),
 | 
						|
			attrNames: keys,
 | 
						|
			idx:       -1,
 | 
						|
		}
 | 
						|
	default:
 | 
						|
		panic("attempt to iterate on non-collection, non-tuple type")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type listElementIterator struct {
 | 
						|
	ety  Type
 | 
						|
	vals []interface{}
 | 
						|
	idx  int
 | 
						|
}
 | 
						|
 | 
						|
func (it *listElementIterator) Element() (Value, Value) {
 | 
						|
	i := it.idx
 | 
						|
	return NumberIntVal(int64(i)), Value{
 | 
						|
		ty: it.ety,
 | 
						|
		v:  it.vals[i],
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (it *listElementIterator) Next() bool {
 | 
						|
	it.idx++
 | 
						|
	return it.idx < len(it.vals)
 | 
						|
}
 | 
						|
 | 
						|
type mapElementIterator struct {
 | 
						|
	ety  Type
 | 
						|
	vals map[string]interface{}
 | 
						|
	keys []string
 | 
						|
	idx  int
 | 
						|
}
 | 
						|
 | 
						|
func (it *mapElementIterator) Element() (Value, Value) {
 | 
						|
	key := it.keys[it.idx]
 | 
						|
	return StringVal(key), Value{
 | 
						|
		ty: it.ety,
 | 
						|
		v:  it.vals[key],
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (it *mapElementIterator) Next() bool {
 | 
						|
	it.idx++
 | 
						|
	return it.idx < len(it.keys)
 | 
						|
}
 | 
						|
 | 
						|
type setElementIterator struct {
 | 
						|
	ety   Type
 | 
						|
	setIt *set.Iterator
 | 
						|
}
 | 
						|
 | 
						|
func (it *setElementIterator) Element() (Value, Value) {
 | 
						|
	val := Value{
 | 
						|
		ty: it.ety,
 | 
						|
		v:  it.setIt.Value(),
 | 
						|
	}
 | 
						|
	return val, val
 | 
						|
}
 | 
						|
 | 
						|
func (it *setElementIterator) Next() bool {
 | 
						|
	return it.setIt.Next()
 | 
						|
}
 | 
						|
 | 
						|
type tupleElementIterator struct {
 | 
						|
	etys []Type
 | 
						|
	vals []interface{}
 | 
						|
	idx  int
 | 
						|
}
 | 
						|
 | 
						|
func (it *tupleElementIterator) Element() (Value, Value) {
 | 
						|
	i := it.idx
 | 
						|
	return NumberIntVal(int64(i)), Value{
 | 
						|
		ty: it.etys[i],
 | 
						|
		v:  it.vals[i],
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (it *tupleElementIterator) Next() bool {
 | 
						|
	it.idx++
 | 
						|
	return it.idx < len(it.vals)
 | 
						|
}
 | 
						|
 | 
						|
type objectElementIterator struct {
 | 
						|
	atys      map[string]Type
 | 
						|
	vals      map[string]interface{}
 | 
						|
	attrNames []string
 | 
						|
	idx       int
 | 
						|
}
 | 
						|
 | 
						|
func (it *objectElementIterator) Element() (Value, Value) {
 | 
						|
	key := it.attrNames[it.idx]
 | 
						|
	return StringVal(key), Value{
 | 
						|
		ty: it.atys[key],
 | 
						|
		v:  it.vals[key],
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (it *objectElementIterator) Next() bool {
 | 
						|
	it.idx++
 | 
						|
	return it.idx < len(it.attrNames)
 | 
						|
}
 |