100 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			100 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package convert
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"html/template"
 | |
| 	"reflect"
 | |
| 	"strconv"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	errorType       = reflect.TypeOf((*error)(nil)).Elem()
 | |
| 	fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
 | |
| )
 | |
| 
 | |
| // Copied from html/template/content.go.
 | |
| // indirectToStringerOrError returns the value, after dereferencing as many times
 | |
| // as necessary to reach the base type (or nil) or an implementation of fmt.Stringer
 | |
| // or error,
 | |
| func indirectToStringerOrError(a any) any {
 | |
| 	if a == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 	v := reflect.ValueOf(a)
 | |
| 	for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Pointer && !v.IsNil() {
 | |
| 		v = v.Elem()
 | |
| 	}
 | |
| 	return v.Interface()
 | |
| }
 | |
| 
 | |
| // ToStringE converts any type to a string type.
 | |
| func ToStringE(i any) (string, error) {
 | |
| 	i = indirectToStringerOrError(i)
 | |
| 
 | |
| 	switch s := i.(type) {
 | |
| 	case string:
 | |
| 		return s, nil
 | |
| 	case bool:
 | |
| 		return strconv.FormatBool(s), nil
 | |
| 	case float64:
 | |
| 		return strconv.FormatFloat(s, 'f', -1, 64), nil
 | |
| 	case float32:
 | |
| 		return strconv.FormatFloat(float64(s), 'f', -1, 32), nil
 | |
| 	case int:
 | |
| 		return strconv.Itoa(s), nil
 | |
| 	case int64:
 | |
| 		return strconv.FormatInt(s, 10), nil
 | |
| 	case int32:
 | |
| 		return strconv.Itoa(int(s)), nil
 | |
| 	case int16:
 | |
| 		return strconv.FormatInt(int64(s), 10), nil
 | |
| 	case int8:
 | |
| 		return strconv.FormatInt(int64(s), 10), nil
 | |
| 	case uint:
 | |
| 		return strconv.FormatUint(uint64(s), 10), nil
 | |
| 	case uint64:
 | |
| 		return strconv.FormatUint(uint64(s), 10), nil
 | |
| 	case uint32:
 | |
| 		return strconv.FormatUint(uint64(s), 10), nil
 | |
| 	case uint16:
 | |
| 		return strconv.FormatUint(uint64(s), 10), nil
 | |
| 	case uint8:
 | |
| 		return strconv.FormatUint(uint64(s), 10), nil
 | |
| 	case json.Number:
 | |
| 		return s.String(), nil
 | |
| 	case []byte:
 | |
| 		return string(s), nil
 | |
| 	case template.HTML:
 | |
| 		return string(s), nil
 | |
| 	case template.URL:
 | |
| 		return string(s), nil
 | |
| 	case template.JS:
 | |
| 		return string(s), nil
 | |
| 	case template.CSS:
 | |
| 		return string(s), nil
 | |
| 	case template.HTMLAttr:
 | |
| 		return string(s), nil
 | |
| 	case nil:
 | |
| 		return "", nil
 | |
| 	case fmt.Stringer:
 | |
| 		return s.String(), nil
 | |
| 	case error:
 | |
| 		return s.Error(), nil
 | |
| 	default:
 | |
| 		return "", fmt.Errorf("unable to cast %#v of type %T to string", i, i)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // ToStringE converts any type to a string type.
 | |
| func ToByteE(i any) ([]byte, error) {
 | |
| 	i = indirectToStringerOrError(i)
 | |
| 
 | |
| 	switch s := i.(type) {
 | |
| 	case []byte:
 | |
| 		return s, nil
 | |
| 	default:
 | |
| 		return nil, fmt.Errorf("unable to cast %#v of type %T to string", i, i)
 | |
| 	}
 | |
| }
 | 
