github.com/v2pro/plz@v0.0.0-20221028024117-e5f9aec5b631/msgfmt/jsonfmt/encoder_bytes.go (about) 1 package jsonfmt 2 3 import ( 4 "unsafe" 5 "unicode/utf8" 6 "context" 7 ) 8 9 type bytesEncoder struct { 10 } 11 12 func (encoder *bytesEncoder) Encode(ctx context.Context, space []byte, ptr unsafe.Pointer) []byte { 13 return WriteBytes(space, *(*[]byte)(ptr)) 14 } 15 16 func WriteBytes(space []byte, s []byte) []byte { 17 space = append(space, '"') 18 // write string, the fast path, without utf8 and escape support 19 var i int 20 var c byte 21 for i, c = range s { 22 if c < utf8.RuneSelf && safeSet[c] { 23 space = append(space, c) 24 } else { 25 break 26 } 27 } 28 if i == len(s)-1 { 29 space = append(space, '"') 30 return space 31 } 32 return writeBytesSlowPath(space, s[i:]) 33 } 34 35 func writeBytesSlowPath(space []byte, s []byte) []byte { 36 start := 0 37 // for the remaining parts, we process them char by char 38 var i int 39 var b byte 40 for i, b = range s { 41 if b >= utf8.RuneSelf { 42 space = append(space, '\\', '\\', 'x', hex[b>>4], hex[b&0xF]) 43 start = i + 1 44 continue 45 } 46 if safeSet[b] { 47 continue 48 } 49 if start < i { 50 space = append(space, s[start:i]...) 51 } 52 switch b { 53 case '\\', '"': 54 space = append(space, '\\', b) 55 case '\n': 56 space = append(space, '\\', 'n') 57 case '\r': 58 space = append(space, '\\', 'r') 59 case '\t': 60 space = append(space, '\\', 't') 61 default: 62 // This encodes bytes < 0x20 except for \t, \n and \r. 63 space = append(space, '\\', '\\', 'x', hex[b>>4], hex[b&0xF]) 64 } 65 start = i + 1 66 } 67 if start < len(s) { 68 space = append(space, s[start:]...) 69 } 70 return append(space, '"') 71 }