func hilFuncMapFlatten() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeString, ast.TypeString, ast.TypeMap},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			kvSep := args[0].(string)
			tupleSep := args[1].(string)
			unwrapped, err := hilToInterface(args[2])
			if err != nil {
				return nil, err
			}
			outArr := []string{}
			for k, v := range unwrapped.(map[string]interface{}) {
				outArr = append(outArr, fmt.Sprintf("%v%s%v", k, kvSep, v))
			}
			sort.Strings(outArr)
			return strings.Join(outArr, tupleSep), nil
		},
	}
}
hilFuncMapFlatten flattens a map into a string of key/value pairs with
given separators.
package interpolation
import (
	"crypto/rand"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"net/url"
	"regexp"
	"sort"
	"strings"
	"sync/atomic"
	"time"
	"github.com/hashicorp/hil"
	"github.com/hashicorp/hil/ast"
	"github.com/spf13/cast"
)
var hilStandardLibrary = createStandardLibrary()
func createStandardLibrary() map[string]ast.Function {
	return map[string]ast.Function{
		"time.nano":       hilFuncTimeNano(),
		"str.truncate":    hilFuncStrTruncate(),
		"str.queryEscape": hilFuncStrQueryEscape(),
		"regexp.matches":  hilFuncRegexpMatches(),
		"counter.next":    hilFuncCounterNext(),
		"rand.base64":     hilFuncRandBase64(),
		"assert":          hilFuncAssert(),
		"json.marshal":    hilFuncJSONMarshal(),
		"map.flatten":     hilFuncMapFlatten(),
	}
}
func hilFuncTimeNano() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			return fmt.Sprintf("%d", time.Now().UnixNano()), nil
		},
	}
}
func hilFuncStrTruncate() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeInt, ast.TypeString},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			maxLength := args[0].(int)
			str := args[1].(string)
			if len(str) > maxLength {
				return str[:maxLength], nil
			}
			return str, nil
		},
	}
}
func hilFuncRegexpMatches() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeString, ast.TypeString},
		ReturnType: ast.TypeBool,
		Callback: func(args []interface{}) (interface{}, error) {
			return regexp.MatchString(args[0].(string), args[1].(string))
		},
	}
}
func hilFuncCounterNext() ast.Function {
	var counter int32
	return ast.Function{
		ArgTypes:   []ast.Type{},
		ReturnType: ast.TypeInt,
		Callback: func(args []interface{}) (interface{}, error) {
			return cast.ToIntE(atomic.AddInt32(&counter, 1))
		},
	}
}
func hilFuncRandBase64() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeInt},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			passwordLength := args[0].(int)
			rb := make([]byte, passwordLength)
			if _, err := rand.Read(rb); err != nil {
				return "", err
			}
			return base64.URLEncoding.EncodeToString(rb), nil
		},
	}
}
func hilFuncStrQueryEscape() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeString},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			return url.QueryEscape(args[0].(string)), nil
		},
	}
}
func hilFuncAssert() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeBool, ast.TypeString},
		ReturnType: ast.TypeBool,
		Callback: func(args []interface{}) (interface{}, error) {
			condition := args[0].(bool)
			message := args[1].(string)
			if !condition {
				return false, fmt.Errorf("Assertion failed: %s", message)
			}
			return true, nil
		},
	}
}
func hilFuncJSONMarshal() ast.Function {
	return ast.Function{
		ArgTypes:   []ast.Type{ast.TypeAny},
		ReturnType: ast.TypeString,
		Callback: func(args []interface{}) (interface{}, error) {
			unwrapped, err := hilToInterface(args[0])
			if err != nil {
				return nil, err
			}
			bytes, err := json.Marshal(unwrapped)
			if err != nil {
				return nil, fmt.Errorf("couldn't convert: %v to JSON %s", args[0], err)
			}
			return string(bytes), nil
		},
	}
}