github.com/hashicorp/packer@v1.14.3/hcl2template/function/length.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package function
     5  
     6  import (
     7  	"errors"
     8  
     9  	"github.com/zclconf/go-cty/cty"
    10  	"github.com/zclconf/go-cty/cty/function"
    11  	"github.com/zclconf/go-cty/cty/function/stdlib"
    12  )
    13  
    14  var LengthFunc = function.New(&function.Spec{
    15  	Params: []function.Parameter{
    16  		{
    17  			Name:             "value",
    18  			Type:             cty.DynamicPseudoType,
    19  			AllowDynamicType: true,
    20  			AllowUnknown:     true,
    21  		},
    22  	},
    23  	Type: func(args []cty.Value) (cty.Type, error) {
    24  		collTy := args[0].Type()
    25  		switch {
    26  		case collTy == cty.String || collTy.IsTupleType() || collTy.IsObjectType() || collTy.IsListType() || collTy.IsMapType() || collTy.IsSetType() || collTy == cty.DynamicPseudoType:
    27  			return cty.Number, nil
    28  		default:
    29  			return cty.Number, errors.New("argument must be a string, a collection type, or a structural type")
    30  		}
    31  	},
    32  	RefineResult: refineNotNull,
    33  	Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
    34  		coll := args[0]
    35  		collTy := args[0].Type()
    36  		switch {
    37  		case collTy == cty.DynamicPseudoType:
    38  			return cty.UnknownVal(cty.Number), nil
    39  		case collTy.IsTupleType():
    40  			l := len(collTy.TupleElementTypes())
    41  			return cty.NumberIntVal(int64(l)), nil
    42  		case collTy.IsObjectType():
    43  			l := len(collTy.AttributeTypes())
    44  			return cty.NumberIntVal(int64(l)), nil
    45  		case collTy == cty.String:
    46  			// We'll delegate to the cty stdlib strlen function here, because
    47  			// it deals with all of the complexities of tokenizing unicode
    48  			// grapheme clusters.
    49  			return stdlib.Strlen(coll)
    50  		case collTy.IsListType() || collTy.IsSetType() || collTy.IsMapType():
    51  			return coll.Length(), nil
    52  		default:
    53  			// Should never happen, because of the checks in our Type func above
    54  			return cty.UnknownVal(cty.Number), errors.New("impossible value type for length(...)")
    55  		}
    56  	},
    57  })
    58  
    59  // Length returns the number of elements in the given collection or number of
    60  // Unicode characters in the given string.
    61  func Length(collection cty.Value) (cty.Value, error) {
    62  	return LengthFunc.Call([]cty.Value{collection})
    63  }