forked from ebhomengo/niki
1
0
Fork 0
niki/vendor/github.com/valyala/fasttemplate/template.go

784 lines
14 KiB
Go
Raw Normal View History

2024-02-18 10:42:21 +00:00
// Package fasttemplate implements simple and fast template library.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Fasttemplate is faster than text/template, strings.Replace
2024-02-18 10:42:21 +00:00
// and strings.Replacer.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Fasttemplate ideally fits for fast and simple placeholders' substitutions.
2024-02-18 10:42:21 +00:00
package fasttemplate
import (
"bytes"
"fmt"
"io"
"github.com/valyala/bytebufferpool"
)
// ExecuteFunc calls f on each template tag (placeholder) occurrence.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Returns the number of bytes written to w.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// This function is optimized for constantly changing templates.
2024-02-18 10:42:21 +00:00
// Use Template.ExecuteFunc for frozen templates.
2024-02-18 10:42:21 +00:00
func ExecuteFunc(template, startTag, endTag string, w io.Writer, f TagFunc) (int64, error) {
2024-02-18 10:42:21 +00:00
s := unsafeString2Bytes(template)
2024-02-18 10:42:21 +00:00
a := unsafeString2Bytes(startTag)
2024-02-18 10:42:21 +00:00
b := unsafeString2Bytes(endTag)
var nn int64
2024-02-18 10:42:21 +00:00
var ni int
2024-02-18 10:42:21 +00:00
var err error
2024-02-18 10:42:21 +00:00
for {
2024-02-18 10:42:21 +00:00
n := bytes.Index(s, a)
2024-02-18 10:42:21 +00:00
if n < 0 {
2024-02-18 10:42:21 +00:00
break
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
ni, err = w.Write(s[:n])
2024-02-18 10:42:21 +00:00
nn += int64(ni)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nn, err
2024-02-18 10:42:21 +00:00
}
s = s[n+len(a):]
2024-02-18 10:42:21 +00:00
n = bytes.Index(s, b)
2024-02-18 10:42:21 +00:00
if n < 0 {
2024-02-18 10:42:21 +00:00
// cannot find end tag - just write it to the output.
2024-02-18 10:42:21 +00:00
ni, _ = w.Write(a)
2024-02-18 10:42:21 +00:00
nn += int64(ni)
2024-02-18 10:42:21 +00:00
break
2024-02-18 10:42:21 +00:00
}
ni, err = f(w, unsafeBytes2String(s[:n]))
2024-02-18 10:42:21 +00:00
nn += int64(ni)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nn, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
s = s[n+len(b):]
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
ni, err = w.Write(s)
2024-02-18 10:42:21 +00:00
nn += int64(ni)
return nn, err
2024-02-18 10:42:21 +00:00
}
// Execute substitutes template tags (placeholders) with the corresponding
2024-02-18 10:42:21 +00:00
// values from the map m and writes the result to the given writer w.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Substitution map m may contain values with the following types:
2024-06-14 08:41:36 +00:00
// - []byte - the fastest value type
2024-06-14 08:41:36 +00:00
// - string - convenient value type
2024-06-14 08:41:36 +00:00
// - TagFunc - flexible value type
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Returns the number of bytes written to w.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// This function is optimized for constantly changing templates.
2024-02-18 10:42:21 +00:00
// Use Template.Execute for frozen templates.
2024-02-18 10:42:21 +00:00
func Execute(template, startTag, endTag string, w io.Writer, m map[string]interface{}) (int64, error) {
2024-02-18 10:42:21 +00:00
return ExecuteFunc(template, startTag, endTag, w, func(w io.Writer, tag string) (int, error) { return stdTagFunc(w, tag, m) })
2024-02-18 10:42:21 +00:00
}
// ExecuteStd works the same way as Execute, but keeps the unknown placeholders.
2024-02-18 10:42:21 +00:00
// This can be used as a drop-in replacement for strings.Replacer
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Substitution map m may contain values with the following types:
2024-06-14 08:41:36 +00:00
// - []byte - the fastest value type
2024-06-14 08:41:36 +00:00
// - string - convenient value type
2024-06-14 08:41:36 +00:00
// - TagFunc - flexible value type
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Returns the number of bytes written to w.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// This function is optimized for constantly changing templates.
2024-02-18 10:42:21 +00:00
// Use Template.ExecuteStd for frozen templates.
2024-02-18 10:42:21 +00:00
func ExecuteStd(template, startTag, endTag string, w io.Writer, m map[string]interface{}) (int64, error) {
2024-02-18 10:42:21 +00:00
return ExecuteFunc(template, startTag, endTag, w, func(w io.Writer, tag string) (int, error) { return keepUnknownTagFunc(w, startTag, endTag, tag, m) })
2024-02-18 10:42:21 +00:00
}
// ExecuteFuncString calls f on each template tag (placeholder) occurrence
2024-02-18 10:42:21 +00:00
// and substitutes it with the data written to TagFunc's w.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Returns the resulting string.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// This function is optimized for constantly changing templates.
2024-02-18 10:42:21 +00:00
// Use Template.ExecuteFuncString for frozen templates.
2024-02-18 10:42:21 +00:00
func ExecuteFuncString(template, startTag, endTag string, f TagFunc) string {
2024-02-18 10:42:21 +00:00
s, err := ExecuteFuncStringWithErr(template, startTag, endTag, f)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
panic(fmt.Sprintf("unexpected error: %s", err))
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return s
2024-02-18 10:42:21 +00:00
}
// ExecuteFuncStringWithErr is nearly the same as ExecuteFuncString
2024-02-18 10:42:21 +00:00
// but when f returns an error, ExecuteFuncStringWithErr won't panic like ExecuteFuncString
2024-02-18 10:42:21 +00:00
// it just returns an empty string and the error f returned
2024-02-18 10:42:21 +00:00
func ExecuteFuncStringWithErr(template, startTag, endTag string, f TagFunc) (string, error) {
2024-02-18 10:42:21 +00:00
if n := bytes.Index(unsafeString2Bytes(template), unsafeString2Bytes(startTag)); n < 0 {
2024-02-18 10:42:21 +00:00
return template, nil
2024-02-18 10:42:21 +00:00
}
bb := byteBufferPool.Get()
2024-02-18 10:42:21 +00:00
if _, err := ExecuteFunc(template, startTag, endTag, bb, f); err != nil {
2024-02-18 10:42:21 +00:00
bb.Reset()
2024-02-18 10:42:21 +00:00
byteBufferPool.Put(bb)
2024-02-18 10:42:21 +00:00
return "", err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
s := string(bb.B)
2024-02-18 10:42:21 +00:00
bb.Reset()
2024-02-18 10:42:21 +00:00
byteBufferPool.Put(bb)
2024-02-18 10:42:21 +00:00
return s, nil
2024-02-18 10:42:21 +00:00
}
var byteBufferPool bytebufferpool.Pool
// ExecuteString substitutes template tags (placeholders) with the corresponding
2024-02-18 10:42:21 +00:00
// values from the map m and returns the result.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Substitution map m may contain values with the following types:
2024-06-14 08:41:36 +00:00
// - []byte - the fastest value type
2024-06-14 08:41:36 +00:00
// - string - convenient value type
2024-06-14 08:41:36 +00:00
// - TagFunc - flexible value type
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// This function is optimized for constantly changing templates.
2024-02-18 10:42:21 +00:00
// Use Template.ExecuteString for frozen templates.
2024-02-18 10:42:21 +00:00
func ExecuteString(template, startTag, endTag string, m map[string]interface{}) string {
2024-02-18 10:42:21 +00:00
return ExecuteFuncString(template, startTag, endTag, func(w io.Writer, tag string) (int, error) { return stdTagFunc(w, tag, m) })
2024-02-18 10:42:21 +00:00
}
// ExecuteStringStd works the same way as ExecuteString, but keeps the unknown placeholders.
2024-02-18 10:42:21 +00:00
// This can be used as a drop-in replacement for strings.Replacer
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Substitution map m may contain values with the following types:
2024-06-14 08:41:36 +00:00
// - []byte - the fastest value type
2024-06-14 08:41:36 +00:00
// - string - convenient value type
2024-06-14 08:41:36 +00:00
// - TagFunc - flexible value type
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// This function is optimized for constantly changing templates.
2024-02-18 10:42:21 +00:00
// Use Template.ExecuteStringStd for frozen templates.
2024-02-18 10:42:21 +00:00
func ExecuteStringStd(template, startTag, endTag string, m map[string]interface{}) string {
2024-02-18 10:42:21 +00:00
return ExecuteFuncString(template, startTag, endTag, func(w io.Writer, tag string) (int, error) { return keepUnknownTagFunc(w, startTag, endTag, tag, m) })
2024-02-18 10:42:21 +00:00
}
// Template implements simple template engine, which can be used for fast
2024-02-18 10:42:21 +00:00
// tags' (aka placeholders) substitution.
2024-02-18 10:42:21 +00:00
type Template struct {
template string
2024-02-18 10:42:21 +00:00
startTag string
endTag string
texts [][]byte
tags []string
2024-02-18 10:42:21 +00:00
byteBufferPool bytebufferpool.Pool
}
// New parses the given template using the given startTag and endTag
2024-02-18 10:42:21 +00:00
// as tag start and tag end.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// The returned template can be executed by concurrently running goroutines
2024-02-18 10:42:21 +00:00
// using Execute* methods.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// New panics if the given template cannot be parsed. Use NewTemplate instead
2024-02-18 10:42:21 +00:00
// if template may contain errors.
2024-02-18 10:42:21 +00:00
func New(template, startTag, endTag string) *Template {
2024-02-18 10:42:21 +00:00
t, err := NewTemplate(template, startTag, endTag)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
panic(err)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return t
2024-02-18 10:42:21 +00:00
}
// NewTemplate parses the given template using the given startTag and endTag
2024-02-18 10:42:21 +00:00
// as tag start and tag end.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// The returned template can be executed by concurrently running goroutines
2024-02-18 10:42:21 +00:00
// using Execute* methods.
2024-02-18 10:42:21 +00:00
func NewTemplate(template, startTag, endTag string) (*Template, error) {
2024-02-18 10:42:21 +00:00
var t Template
2024-02-18 10:42:21 +00:00
err := t.Reset(template, startTag, endTag)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nil, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return &t, nil
2024-02-18 10:42:21 +00:00
}
// TagFunc can be used as a substitution value in the map passed to Execute*.
2024-02-18 10:42:21 +00:00
// Execute* functions pass tag (placeholder) name in 'tag' argument.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// TagFunc must be safe to call from concurrently running goroutines.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// TagFunc must write contents to w and return the number of bytes written.
2024-02-18 10:42:21 +00:00
type TagFunc func(w io.Writer, tag string) (int, error)
// Reset resets the template t to new one defined by
2024-02-18 10:42:21 +00:00
// template, startTag and endTag.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Reset allows Template object re-use.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Reset may be called only if no other goroutines call t methods at the moment.
2024-02-18 10:42:21 +00:00
func (t *Template) Reset(template, startTag, endTag string) error {
2024-02-18 10:42:21 +00:00
// Keep these vars in t, so GC won't collect them and won't break
2024-02-18 10:42:21 +00:00
// vars derived via unsafe*
2024-02-18 10:42:21 +00:00
t.template = template
2024-02-18 10:42:21 +00:00
t.startTag = startTag
2024-02-18 10:42:21 +00:00
t.endTag = endTag
2024-02-18 10:42:21 +00:00
t.texts = t.texts[:0]
2024-02-18 10:42:21 +00:00
t.tags = t.tags[:0]
if len(startTag) == 0 {
2024-02-18 10:42:21 +00:00
panic("startTag cannot be empty")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if len(endTag) == 0 {
2024-02-18 10:42:21 +00:00
panic("endTag cannot be empty")
2024-02-18 10:42:21 +00:00
}
s := unsafeString2Bytes(template)
2024-02-18 10:42:21 +00:00
a := unsafeString2Bytes(startTag)
2024-02-18 10:42:21 +00:00
b := unsafeString2Bytes(endTag)
tagsCount := bytes.Count(s, a)
2024-02-18 10:42:21 +00:00
if tagsCount == 0 {
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
if tagsCount+1 > cap(t.texts) {
2024-02-18 10:42:21 +00:00
t.texts = make([][]byte, 0, tagsCount+1)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if tagsCount > cap(t.tags) {
2024-02-18 10:42:21 +00:00
t.tags = make([]string, 0, tagsCount)
2024-02-18 10:42:21 +00:00
}
for {
2024-02-18 10:42:21 +00:00
n := bytes.Index(s, a)
2024-02-18 10:42:21 +00:00
if n < 0 {
2024-02-18 10:42:21 +00:00
t.texts = append(t.texts, s)
2024-02-18 10:42:21 +00:00
break
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
t.texts = append(t.texts, s[:n])
s = s[n+len(a):]
2024-02-18 10:42:21 +00:00
n = bytes.Index(s, b)
2024-02-18 10:42:21 +00:00
if n < 0 {
2024-02-18 10:42:21 +00:00
return fmt.Errorf("Cannot find end tag=%q in the template=%q starting from %q", endTag, template, s)
2024-02-18 10:42:21 +00:00
}
t.tags = append(t.tags, unsafeBytes2String(s[:n]))
2024-02-18 10:42:21 +00:00
s = s[n+len(b):]
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
// ExecuteFunc calls f on each template tag (placeholder) occurrence.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Returns the number of bytes written to w.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// This function is optimized for frozen templates.
2024-02-18 10:42:21 +00:00
// Use ExecuteFunc for constantly changing templates.
2024-02-18 10:42:21 +00:00
func (t *Template) ExecuteFunc(w io.Writer, f TagFunc) (int64, error) {
2024-02-18 10:42:21 +00:00
var nn int64
n := len(t.texts) - 1
2024-02-18 10:42:21 +00:00
if n == -1 {
2024-02-18 10:42:21 +00:00
ni, err := w.Write(unsafeString2Bytes(t.template))
2024-02-18 10:42:21 +00:00
return int64(ni), err
2024-02-18 10:42:21 +00:00
}
for i := 0; i < n; i++ {
2024-02-18 10:42:21 +00:00
ni, err := w.Write(t.texts[i])
2024-02-18 10:42:21 +00:00
nn += int64(ni)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nn, err
2024-02-18 10:42:21 +00:00
}
ni, err = f(w, t.tags[i])
2024-02-18 10:42:21 +00:00
nn += int64(ni)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return nn, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
ni, err := w.Write(t.texts[n])
2024-02-18 10:42:21 +00:00
nn += int64(ni)
2024-02-18 10:42:21 +00:00
return nn, err
2024-02-18 10:42:21 +00:00
}
// Execute substitutes template tags (placeholders) with the corresponding
2024-02-18 10:42:21 +00:00
// values from the map m and writes the result to the given writer w.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Substitution map m may contain values with the following types:
2024-06-14 08:41:36 +00:00
// - []byte - the fastest value type
2024-06-14 08:41:36 +00:00
// - string - convenient value type
2024-06-14 08:41:36 +00:00
// - TagFunc - flexible value type
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Returns the number of bytes written to w.
2024-02-18 10:42:21 +00:00
func (t *Template) Execute(w io.Writer, m map[string]interface{}) (int64, error) {
2024-02-18 10:42:21 +00:00
return t.ExecuteFunc(w, func(w io.Writer, tag string) (int, error) { return stdTagFunc(w, tag, m) })
2024-02-18 10:42:21 +00:00
}
// ExecuteStd works the same way as Execute, but keeps the unknown placeholders.
2024-02-18 10:42:21 +00:00
// This can be used as a drop-in replacement for strings.Replacer
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Substitution map m may contain values with the following types:
2024-06-14 08:41:36 +00:00
// - []byte - the fastest value type
2024-06-14 08:41:36 +00:00
// - string - convenient value type
2024-06-14 08:41:36 +00:00
// - TagFunc - flexible value type
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Returns the number of bytes written to w.
2024-02-18 10:42:21 +00:00
func (t *Template) ExecuteStd(w io.Writer, m map[string]interface{}) (int64, error) {
2024-02-18 10:42:21 +00:00
return t.ExecuteFunc(w, func(w io.Writer, tag string) (int, error) { return keepUnknownTagFunc(w, t.startTag, t.endTag, tag, m) })
2024-02-18 10:42:21 +00:00
}
// ExecuteFuncString calls f on each template tag (placeholder) occurrence
2024-02-18 10:42:21 +00:00
// and substitutes it with the data written to TagFunc's w.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Returns the resulting string.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// This function is optimized for frozen templates.
2024-02-18 10:42:21 +00:00
// Use ExecuteFuncString for constantly changing templates.
2024-02-18 10:42:21 +00:00
func (t *Template) ExecuteFuncString(f TagFunc) string {
2024-02-18 10:42:21 +00:00
s, err := t.ExecuteFuncStringWithErr(f)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
panic(fmt.Sprintf("unexpected error: %s", err))
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return s
2024-02-18 10:42:21 +00:00
}
// ExecuteFuncStringWithErr calls f on each template tag (placeholder) occurrence
2024-02-18 10:42:21 +00:00
// and substitutes it with the data written to TagFunc's w.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Returns the resulting string.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// This function is optimized for frozen templates.
2024-02-18 10:42:21 +00:00
// Use ExecuteFuncString for constantly changing templates.
2024-02-18 10:42:21 +00:00
func (t *Template) ExecuteFuncStringWithErr(f TagFunc) (string, error) {
2024-02-18 10:42:21 +00:00
bb := t.byteBufferPool.Get()
2024-02-18 10:42:21 +00:00
if _, err := t.ExecuteFunc(bb, f); err != nil {
2024-02-18 10:42:21 +00:00
bb.Reset()
2024-02-18 10:42:21 +00:00
t.byteBufferPool.Put(bb)
2024-02-18 10:42:21 +00:00
return "", err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
s := string(bb.Bytes())
2024-02-18 10:42:21 +00:00
bb.Reset()
2024-02-18 10:42:21 +00:00
t.byteBufferPool.Put(bb)
2024-02-18 10:42:21 +00:00
return s, nil
2024-02-18 10:42:21 +00:00
}
// ExecuteString substitutes template tags (placeholders) with the corresponding
2024-02-18 10:42:21 +00:00
// values from the map m and returns the result.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Substitution map m may contain values with the following types:
2024-06-14 08:41:36 +00:00
// - []byte - the fastest value type
2024-06-14 08:41:36 +00:00
// - string - convenient value type
2024-06-14 08:41:36 +00:00
// - TagFunc - flexible value type
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// This function is optimized for frozen templates.
2024-02-18 10:42:21 +00:00
// Use ExecuteString for constantly changing templates.
2024-02-18 10:42:21 +00:00
func (t *Template) ExecuteString(m map[string]interface{}) string {
2024-02-18 10:42:21 +00:00
return t.ExecuteFuncString(func(w io.Writer, tag string) (int, error) { return stdTagFunc(w, tag, m) })
2024-02-18 10:42:21 +00:00
}
// ExecuteStringStd works the same way as ExecuteString, but keeps the unknown placeholders.
2024-02-18 10:42:21 +00:00
// This can be used as a drop-in replacement for strings.Replacer
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Substitution map m may contain values with the following types:
2024-06-14 08:41:36 +00:00
// - []byte - the fastest value type
2024-06-14 08:41:36 +00:00
// - string - convenient value type
2024-06-14 08:41:36 +00:00
// - TagFunc - flexible value type
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// This function is optimized for frozen templates.
2024-02-18 10:42:21 +00:00
// Use ExecuteStringStd for constantly changing templates.
2024-02-18 10:42:21 +00:00
func (t *Template) ExecuteStringStd(m map[string]interface{}) string {
2024-02-18 10:42:21 +00:00
return t.ExecuteFuncString(func(w io.Writer, tag string) (int, error) { return keepUnknownTagFunc(w, t.startTag, t.endTag, tag, m) })
2024-02-18 10:42:21 +00:00
}
func stdTagFunc(w io.Writer, tag string, m map[string]interface{}) (int, error) {
2024-02-18 10:42:21 +00:00
v := m[tag]
2024-02-18 10:42:21 +00:00
if v == nil {
2024-02-18 10:42:21 +00:00
return 0, nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
switch value := v.(type) {
2024-02-18 10:42:21 +00:00
case []byte:
2024-02-18 10:42:21 +00:00
return w.Write(value)
2024-02-18 10:42:21 +00:00
case string:
2024-02-18 10:42:21 +00:00
return w.Write([]byte(value))
2024-02-18 10:42:21 +00:00
case TagFunc:
2024-02-18 10:42:21 +00:00
return value(w, tag)
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
panic(fmt.Sprintf("tag=%q contains unexpected value type=%#v. Expected []byte, string or TagFunc", tag, v))
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
func keepUnknownTagFunc(w io.Writer, startTag, endTag, tag string, m map[string]interface{}) (int, error) {
2024-02-18 10:42:21 +00:00
v, ok := m[tag]
2024-02-18 10:42:21 +00:00
if !ok {
2024-02-18 10:42:21 +00:00
if _, err := w.Write(unsafeString2Bytes(startTag)); err != nil {
2024-02-18 10:42:21 +00:00
return 0, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if _, err := w.Write(unsafeString2Bytes(tag)); err != nil {
2024-02-18 10:42:21 +00:00
return 0, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if _, err := w.Write(unsafeString2Bytes(endTag)); err != nil {
2024-02-18 10:42:21 +00:00
return 0, err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return len(startTag) + len(tag) + len(endTag), nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if v == nil {
2024-02-18 10:42:21 +00:00
return 0, nil
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
switch value := v.(type) {
2024-02-18 10:42:21 +00:00
case []byte:
2024-02-18 10:42:21 +00:00
return w.Write(value)
2024-02-18 10:42:21 +00:00
case string:
2024-02-18 10:42:21 +00:00
return w.Write([]byte(value))
2024-02-18 10:42:21 +00:00
case TagFunc:
2024-02-18 10:42:21 +00:00
return value(w, tag)
2024-02-18 10:42:21 +00:00
default:
2024-02-18 10:42:21 +00:00
panic(fmt.Sprintf("tag=%q contains unexpected value type=%#v. Expected []byte, string or TagFunc", tag, v))
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}