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) } }