85 lines
2.1 KiB
Go
85 lines
2.1 KiB
Go
|
package raymond
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"reflect"
|
||
|
"strconv"
|
||
|
)
|
||
|
|
||
|
// SafeString represents a string that must not be escaped.
|
||
|
//
|
||
|
// A SafeString can be returned by helpers to disable escaping.
|
||
|
type SafeString string
|
||
|
|
||
|
// isSafeString returns true if argument is a SafeString
|
||
|
func isSafeString(value interface{}) bool {
|
||
|
if _, ok := value.(SafeString); ok {
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// Str returns string representation of any basic type value.
|
||
|
func Str(value interface{}) string {
|
||
|
return strValue(reflect.ValueOf(value))
|
||
|
}
|
||
|
|
||
|
// strValue returns string representation of a reflect.Value
|
||
|
func strValue(value reflect.Value) string {
|
||
|
result := ""
|
||
|
|
||
|
ival, ok := printableValue(value)
|
||
|
if !ok {
|
||
|
panic(fmt.Errorf("Can't print value: %q", value))
|
||
|
}
|
||
|
|
||
|
val := reflect.ValueOf(ival)
|
||
|
|
||
|
switch val.Kind() {
|
||
|
case reflect.Array, reflect.Slice:
|
||
|
for i := 0; i < val.Len(); i++ {
|
||
|
result += strValue(val.Index(i))
|
||
|
}
|
||
|
case reflect.Bool:
|
||
|
result = "false"
|
||
|
if val.Bool() {
|
||
|
result = "true"
|
||
|
}
|
||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||
|
result = fmt.Sprintf("%d", ival)
|
||
|
case reflect.Float32, reflect.Float64:
|
||
|
result = strconv.FormatFloat(val.Float(), 'f', -1, 64)
|
||
|
case reflect.Invalid:
|
||
|
result = ""
|
||
|
default:
|
||
|
result = fmt.Sprintf("%s", ival)
|
||
|
}
|
||
|
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
// printableValue returns the, possibly indirected, interface value inside v that
|
||
|
// is best for a call to formatted printer.
|
||
|
//
|
||
|
// NOTE: borrowed from https://github.com/golang/go/tree/master/src/text/template/exec.go
|
||
|
func printableValue(v reflect.Value) (interface{}, bool) {
|
||
|
if v.Kind() == reflect.Ptr {
|
||
|
v, _ = indirect(v) // fmt.Fprint handles nil.
|
||
|
}
|
||
|
if !v.IsValid() {
|
||
|
return "", true
|
||
|
}
|
||
|
|
||
|
if !v.Type().Implements(errorType) && !v.Type().Implements(fmtStringerType) {
|
||
|
if v.CanAddr() && (reflect.PtrTo(v.Type()).Implements(errorType) || reflect.PtrTo(v.Type()).Implements(fmtStringerType)) {
|
||
|
v = v.Addr()
|
||
|
} else {
|
||
|
switch v.Kind() {
|
||
|
case reflect.Chan, reflect.Func:
|
||
|
return nil, false
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return v.Interface(), true
|
||
|
}
|