diff --git a/common/errors/errors.go b/common/errors/errors.go index 265ea8139..aefc1a41c 100644 --- a/common/errors/errors.go +++ b/common/errors/errors.go @@ -4,6 +4,7 @@ package errors // import "v2ray.com/core/common/errors" import ( "os" "reflect" + "strings" "v2ray.com/core/common/log" "v2ray.com/core/common/serial" @@ -41,21 +42,28 @@ func (err *Error) pkgPath() string { // Error implements error.Error(). func (v *Error) Error() string { - msg := serial.Concat(v.message...) - if v.inner != nil { - msg += " > " + v.inner.Error() + builder := strings.Builder{} + for _, prefix := range v.prefix { + builder.WriteByte('[') + builder.WriteString(serial.ToString(prefix)) + builder.WriteString("] ") } + path := v.pkgPath() if len(path) > 0 { - msg = path + ": " + msg + builder.WriteString(path) + builder.WriteString(": ") } - var prefix string - for _, p := range v.prefix { - prefix += "[" + serial.ToString(p) + "] " + msg := serial.Concat(v.message...) + builder.WriteString(msg) + + if v.inner != nil { + builder.WriteString(" > ") + builder.WriteString(v.inner.Error()) } - return prefix + msg + return builder.String() } // Inner implements hasInnerError.Inner() diff --git a/common/serial/string.go b/common/serial/string.go index 490e49c95..509c324ad 100644 --- a/common/serial/string.go +++ b/common/serial/string.go @@ -28,11 +28,11 @@ func ToString(v interface{}) string { } func Concat(v ...interface{}) string { - values := make([]string, len(v)) - for i, value := range v { - values[i] = ToString(value) + builder := strings.Builder{} + for _, value := range v { + builder.WriteString(ToString(value)) } - return strings.Join(values, "") + return builder.String() } func WriteString(s string) func([]byte) (int, error) { diff --git a/common/serial/string_test.go b/common/serial/string_test.go index 47d044683..f35b5eb65 100644 --- a/common/serial/string_test.go +++ b/common/serial/string_test.go @@ -26,3 +26,33 @@ func TestToString(t *testing.T) { assert(ToString(c.Value), Equals, c.String) } } + +func TestConcat(t *testing.T) { + testCases := []struct { + Input []interface{} + Output string + }{ + { + Input: []interface{}{ + "a", "b", + }, + Output: "ab", + }, + } + + for _, testCase := range testCases { + actual := Concat(testCase.Input...) + if actual != testCase.Output { + t.Error("Unexpected output: ", actual, " but want: ", testCase.Output) + } + } +} + +func BenchmarkConcat(b *testing.B) { + input := []interface{}{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"} + + b.ReportAllocs() + for i := 0; i < b.N; i++ { + _ = Concat(input...) + } +}