Skip to content

Commit

Permalink
PoC: Generics instead of unsafe of reflection
Browse files Browse the repository at this point in the history
  • Loading branch information
abhinav committed Sep 9, 2023
1 parent 414a7b5 commit 044300b
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 27 deletions.
2 changes: 1 addition & 1 deletion buffer/buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (b *Buffer) AppendByte(v byte) {
}

// AppendByteV writes a single byte to the Buffer.

Check failure on line 45 in buffer/buffer.go

View workflow job for this annotation

GitHub Actions / Lint

exported: comment on exported method Buffer.AppendBytes should be of the form "AppendBytes ..." (revive)
func (b *Buffer) AppendByteV(v ...byte) {
func (b *Buffer) AppendBytes(v []byte) {
b.bs = append(b.bs, v...)
}

Expand Down
70 changes: 44 additions & 26 deletions zapcore/json_encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,8 @@ package zapcore
import (
"encoding/base64"
"math"
"reflect"
"time"
"unicode/utf8"
"unsafe"

"go.uber.org/zap/buffer"
"go.uber.org/zap/internal/bufferpool"
Expand Down Expand Up @@ -488,15 +486,35 @@ func (enc *jsonEncoder) appendFloat(val float64, bitSize int) {
// Unlike the standard library's encoder, it doesn't attempt to protect the
// user from browser vulnerabilities or JSONP-related problems.
func (enc *jsonEncoder) safeAddString(s string) {
enc.safeAddByteString(*(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
Data: (*reflect.StringHeader)(unsafe.Pointer(&s)).Data,
Len: len(s),
Cap: len(s),
})))
safeAppendStringLike(
(*buffer.Buffer).AppendString,
utf8.DecodeRuneInString,
enc.buf,
s,
)
}

// safeAddByteString is no-alloc equivalent of safeAddString(string(s)) for s []byte.
func (enc *jsonEncoder) safeAddByteString(s []byte) {
safeAppendStringLike(
(*buffer.Buffer).AppendBytes,
utf8.DecodeRune,
enc.buf,
s,
)
}

// safeAppendStringLike is a generic implementation of safeAddString and safeAddByteString.
// It appends a string or byte slice to the buffer, escaping all special characters.
func safeAppendStringLike[S []byte | string](
// appendTo appends this string-like object to the buffer.
appendTo func(*buffer.Buffer, S),
// decodeRune decodes the next rune from the string-like object
// and returns its value and width in bytes.
decodeRune func(S) (rune, int),
buf *buffer.Buffer,
s S,
) {
start := 0
for i := 0; i < len(s); {
if s[i] < utf8.RuneSelf {
Expand All @@ -505,53 +523,53 @@ func (enc *jsonEncoder) safeAddByteString(s []byte) {
continue
}

enc.buf.AppendByteV(s[start:i]...)
appendTo(buf, s[start:i])

switch s[i] {
case '\\', '"':
enc.buf.AppendByte('\\')
enc.buf.AppendByte(s[i])
buf.AppendByte('\\')
buf.AppendByte(s[i])
case '\n':
enc.buf.AppendByte('\\')
enc.buf.AppendByte('n')
buf.AppendByte('\\')
buf.AppendByte('n')
case '\r':
enc.buf.AppendByte('\\')
enc.buf.AppendByte('r')
buf.AppendByte('\\')
buf.AppendByte('r')
case '\t':
enc.buf.AppendByte('\\')
enc.buf.AppendByte('t')
buf.AppendByte('\\')
buf.AppendByte('t')
default:
// Encode bytes < 0x20, except for the escape sequences above.
enc.buf.AppendString(`\u00`)
enc.buf.AppendByte(_hex[s[i]>>4])
enc.buf.AppendByte(_hex[s[i]&0xF])
buf.AppendString(`\u00`)
buf.AppendByte(_hex[s[i]>>4])
buf.AppendByte(_hex[s[i]&0xF])
}

i++
start = i
continue
}

enc.buf.AppendByteV(s[start:i]...)
appendTo(buf, s[start:i])

r, size := utf8.DecodeRune(s[i:])
if enc.tryAddRuneError(r, size) {
r, size := decodeRune(s[i:])
if tryAddRuneError(buf, r, size) {
i++
start = i
continue
}
enc.buf.Write(s[i : i+size])
appendTo(buf, s[i:i+size])
i += size
start = i
}

// add remaining
enc.buf.AppendByteV(s[start:]...)
appendTo(buf, s[start:])
}

func (enc *jsonEncoder) tryAddRuneError(r rune, size int) bool {
func tryAddRuneError(buf *buffer.Buffer, r rune, size int) bool {
if r == utf8.RuneError && size == 1 {
enc.buf.AppendString(`\ufffd`)
buf.AppendString(`\ufffd`)
return true
}
return false
Expand Down

0 comments on commit 044300b

Please sign in to comment.