From 4d386dd806906f546def27fee11a63bcd618ecbb Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Fri, 30 Oct 2020 15:36:23 +0100 Subject: [PATCH] add length function that can work with more types --- hcl2template/function/length.go | 53 +++++++++++++++++++++++++++++++++ hcl2template/functions.go | 2 +- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 hcl2template/function/length.go diff --git a/hcl2template/function/length.go b/hcl2template/function/length.go new file mode 100644 index 000000000..176326ac8 --- /dev/null +++ b/hcl2template/function/length.go @@ -0,0 +1,53 @@ +package function + +import ( + "errors" + + "github.com/zclconf/go-cty/cty" + "github.com/zclconf/go-cty/cty/function" + "github.com/zclconf/go-cty/cty/function/stdlib" +) + +var LengthFunc = function.New(&function.Spec{ + Params: []function.Parameter{ + { + Name: "value", + Type: cty.DynamicPseudoType, + AllowDynamicType: true, + AllowUnknown: true, + }, + }, + Type: func(args []cty.Value) (cty.Type, error) { + collTy := args[0].Type() + switch { + case collTy == cty.String || collTy.IsTupleType() || collTy.IsObjectType() || collTy.IsListType() || collTy.IsMapType() || collTy.IsSetType() || collTy == cty.DynamicPseudoType: + return cty.Number, nil + default: + return cty.Number, errors.New("argument must be a string, a collection type, or a structural type") + } + }, + Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { + coll := args[0] + collTy := args[0].Type() + switch { + case collTy == cty.DynamicPseudoType: + return cty.UnknownVal(cty.Number), nil + case collTy.IsTupleType(): + l := len(collTy.TupleElementTypes()) + return cty.NumberIntVal(int64(l)), nil + case collTy.IsObjectType(): + l := len(collTy.AttributeTypes()) + return cty.NumberIntVal(int64(l)), nil + case collTy == cty.String: + // We'll delegate to the cty stdlib strlen function here, because + // it deals with all of the complexities of tokenizing unicode + // grapheme clusters. + return stdlib.Strlen(coll) + case collTy.IsListType() || collTy.IsSetType() || collTy.IsMapType(): + return coll.Length(), nil + default: + // Should never happen, because of the checks in our Type func above + return cty.UnknownVal(cty.Number), errors.New("impossible value type for length(...)") + } + }, +}) diff --git a/hcl2template/functions.go b/hcl2template/functions.go index f91abdab7..058a3f8da 100644 --- a/hcl2template/functions.go +++ b/hcl2template/functions.go @@ -68,7 +68,7 @@ func Functions(basedir string) map[string]function.Function { "jsondecode": stdlib.JSONDecodeFunc, "jsonencode": stdlib.JSONEncodeFunc, "keys": stdlib.KeysFunc, - "length": stdlib.LengthFunc, + "length": pkrfunction.LengthFunc, "log": stdlib.LogFunc, "lookup": stdlib.LookupFunc, "lower": stdlib.LowerFunc,