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