blob: cfbfa745bdc4f762e8db20d9cd41c0faadd23e19 [file] [log] [blame]
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fidl
import (
"errors"
"reflect"
"strconv"
"strings"
)
// Usage: printf("abc {} def {} ...", 3, X{4})
func printf(format string, args ...interface{}) {
print(sprintf(format, args...))
}
func errorf(format string, args ...interface{}) error {
return errors.New(sprintf(format, args...))
}
func sprintf(format string, args ...interface{}) string {
var argStrs []string
for _, arg := range args {
argStrs = append(argStrs, buildValueString(reflect.ValueOf(arg)))
}
parts := strings.Split(format, "{}")
argIndex := 0
strIndex := 0
out := ""
for strIndex < len(parts) {
if argIndex >= strIndex {
out += parts[strIndex]
strIndex++
} else {
out += argStrs[argIndex]
argIndex++
}
}
return out
}
func buildTypeString(rt reflect.Type) string {
switch rt.Kind() {
case reflect.Bool:
fallthrough
case reflect.Int:
fallthrough
case reflect.Int8:
fallthrough
case reflect.Int16:
fallthrough
case reflect.Int32:
fallthrough
case reflect.Int64:
fallthrough
case reflect.Uint:
fallthrough
case reflect.Uint8:
fallthrough
case reflect.Uint16:
fallthrough
case reflect.Uint32:
fallthrough
case reflect.Uint64:
fallthrough
case reflect.Uintptr:
fallthrough
case reflect.Float32:
fallthrough
case reflect.Float64:
fallthrough
case reflect.String:
return rt.Kind().String()
case reflect.Array:
return "[" + strconv.FormatUint(uint64(rt.Size()), 10) + "]" + buildTypeString(rt.Elem())
case reflect.Slice:
return "[]" + buildTypeString(rt.Elem())
case reflect.Map:
return "[" + buildTypeString(rt.Key()) + "]" + buildTypeString(rt.Elem())
case reflect.Ptr:
return "*" + buildTypeString(rt.Elem())
case reflect.Interface:
fallthrough
case reflect.Struct:
return rt.Name()
case reflect.Complex64:
return "[complex64]"
case reflect.Complex128:
return "[complex128]"
case reflect.Chan:
return "[chan]"
case reflect.Func:
return "[func]"
case reflect.UnsafePointer:
return "[unsafeptr]"
default:
panic("unsupported type kind " + strconv.Itoa(int(rt.Kind())))
}
}
func buildValueString(rv reflect.Value) string {
switch rv.Kind() {
case reflect.Bool:
return strconv.FormatBool(rv.Bool())
case reflect.Int:
fallthrough
case reflect.Int8:
fallthrough
case reflect.Int16:
fallthrough
case reflect.Int32:
fallthrough
case reflect.Int64:
return strconv.FormatInt(rv.Int(), 10)
case reflect.Uint:
fallthrough
case reflect.Uint8:
fallthrough
case reflect.Uint16:
fallthrough
case reflect.Uint32:
fallthrough
case reflect.Uint64:
return strconv.FormatUint(rv.Uint(), 10)
case reflect.Uintptr:
return "0x" + strconv.FormatUint(rv.Uint(), 16)
case reflect.Float32:
fallthrough
case reflect.Float64:
return strconv.FormatFloat(rv.Float(), 'f', -1, 64)
case reflect.String:
return rv.String() // TODO quote the string
case reflect.Array:
fallthrough
case reflect.Slice:
var valueStrs []string
for i := 0; i < rv.Len(); i++ {
valueStrs = append(valueStrs, buildValueString(rv.Index(i)))
}
return buildTypeString(rv.Type()) + "{" + strings.Join(valueStrs, ", ") + "}"
case reflect.Map:
iter := rv.MapRange()
var itemStrs []string
for iter.Next() {
itemStrs = append(itemStrs, buildValueString(iter.Key())+": "+buildValueString(iter.Value()))
}
return buildTypeString(rv.Type()) + "{" + strings.Join(itemStrs, ", ") + "}"
case reflect.Interface:
fallthrough
case reflect.Ptr:
if rv.IsNil() {
return "nil"
} else {
return buildValueString(rv.Elem())
}
case reflect.Struct:
var itemStrs []string
for i := 0; i < rv.NumField(); i++ {
itemStrs = append(itemStrs, rv.Type().Field(i).Name+": "+buildValueString(rv.Field(i)))
}
return buildTypeString(rv.Type()) + "{" + strings.Join(itemStrs, ", ") + "}"
case reflect.Complex64:
return "[complex64]"
case reflect.Complex128:
return "[complex128]"
case reflect.Chan:
return "[chan]"
case reflect.Func:
return "[func]"
case reflect.UnsafePointer:
return "[unsafeptr]"
default:
panic("unsupported value kind " + strconv.Itoa(int(rv.Kind())))
}
}