github.com/hashicorp/packer@v1.14.3/hcl2template/function/sum.go (about) 1 package function 2 3 import ( 4 "fmt" 5 "math/big" 6 7 "github.com/zclconf/go-cty/cty" 8 "github.com/zclconf/go-cty/cty/convert" 9 "github.com/zclconf/go-cty/cty/function" 10 ) 11 12 var SumFunc = function.New(&function.Spec{ 13 Params: []function.Parameter{ 14 { 15 Name: "list", 16 Type: cty.DynamicPseudoType, 17 }, 18 }, 19 Type: function.StaticReturnType(cty.Number), 20 RefineResult: refineNotNull, 21 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { 22 23 if !args[0].CanIterateElements() { 24 return cty.NilVal, function.NewArgErrorf(0, "cannot sum noniterable") 25 } 26 27 if args[0].LengthInt() == 0 { // Easy path 28 return cty.NilVal, function.NewArgErrorf(0, "cannot sum an empty list") 29 } 30 31 arg := args[0].AsValueSlice() 32 ty := args[0].Type() 33 34 if !ty.IsListType() && !ty.IsSetType() && !ty.IsTupleType() { 35 return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple. Received %s", ty.FriendlyName()) 36 } 37 38 if !args[0].IsWhollyKnown() { 39 return cty.UnknownVal(cty.Number), nil 40 } 41 42 // big.Float.Add can panic if the input values are opposing infinities, 43 // so we must catch that here in order to remain within 44 // the cty Function abstraction. 45 defer func() { 46 if r := recover(); r != nil { 47 if _, ok := r.(big.ErrNaN); ok { 48 ret = cty.NilVal 49 err = fmt.Errorf("can't compute sum of opposing infinities") 50 } else { 51 // not a panic we recognize 52 panic(r) 53 } 54 } 55 }() 56 57 s := arg[0] 58 if s.IsNull() { 59 return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple of number values") 60 } 61 s, err = convert.Convert(s, cty.Number) 62 if err != nil { 63 return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple of number values") 64 } 65 for _, v := range arg[1:] { 66 if v.IsNull() { 67 return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple of number values") 68 } 69 v, err = convert.Convert(v, cty.Number) 70 if err != nil { 71 return cty.NilVal, function.NewArgErrorf(0, "argument must be list, set, or tuple of number values") 72 } 73 s = s.Add(v) 74 } 75 76 return s, nil 77 }, 78 }) 79 80 // Sum adds numbers in a list, set, or tuple 81 func Sum(list cty.Value) (cty.Value, error) { 82 return SumFunc.Call([]cty.Value{list}) 83 }