primitives.go (4644B)
1 /* 2 * Copyright 2021 ByteDance Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package encoder 18 19 import ( 20 `encoding` 21 `encoding/json` 22 `unsafe` 23 24 `github.com/bytedance/sonic/internal/jit` 25 `github.com/bytedance/sonic/internal/native` 26 `github.com/bytedance/sonic/internal/rt` 27 ) 28 29 /** Encoder Primitives **/ 30 31 func encodeNil(rb *[]byte) error { 32 *rb = append(*rb, 'n', 'u', 'l', 'l') 33 return nil 34 } 35 36 func encodeString(buf *[]byte, val string) error { 37 var sidx int 38 var pbuf *rt.GoSlice 39 var pstr *rt.GoString 40 41 /* opening quote */ 42 *buf = append(*buf, '"') 43 pbuf = (*rt.GoSlice)(unsafe.Pointer(buf)) 44 pstr = (*rt.GoString)(unsafe.Pointer(&val)) 45 46 /* encode with native library */ 47 for sidx < pstr.Len { 48 sn := pstr.Len - sidx 49 dn := pbuf.Cap - pbuf.Len 50 sp := padd(pstr.Ptr, sidx) 51 dp := padd(pbuf.Ptr, pbuf.Len) 52 nb := native.Quote(sp, sn, dp, &dn, 0) 53 54 /* check for errors */ 55 if pbuf.Len += dn; nb >= 0 { 56 break 57 } 58 59 /* not enough space, grow the slice and try again */ 60 sidx += ^nb 61 *pbuf = growslice(rt.UnpackType(byteType), *pbuf, pbuf.Cap * 2) 62 } 63 64 /* closing quote */ 65 *buf = append(*buf, '"') 66 return nil 67 } 68 69 func encodeTypedPointer(buf *[]byte, vt *rt.GoType, vp *unsafe.Pointer, sb *_Stack, fv uint64) error { 70 if vt == nil { 71 return encodeNil(buf) 72 } else if fn, err := findOrCompile(vt, (fv&(1<<bitPointerValue)) != 0); err != nil { 73 return err 74 } else if vt.Indirect() { 75 rt.MoreStack(_FP_size + native.MaxFrameSize) 76 rt.StopProf() 77 err := fn(buf, *vp, sb, fv) 78 rt.StartProf() 79 return err 80 } else { 81 rt.MoreStack(_FP_size + native.MaxFrameSize) 82 rt.StopProf() 83 err := fn(buf, unsafe.Pointer(vp), sb, fv) 84 rt.StartProf() 85 return err 86 } 87 } 88 89 func encodeJsonMarshaler(buf *[]byte, val json.Marshaler, opt Options) error { 90 if ret, err := val.MarshalJSON(); err != nil { 91 return err 92 } else { 93 if opt & CompactMarshaler != 0 { 94 return compact(buf, ret) 95 } 96 if ok, s := Valid(ret); !ok { 97 return error_marshaler(ret, s) 98 } 99 *buf = append(*buf, ret...) 100 return nil 101 } 102 } 103 104 func encodeTextMarshaler(buf *[]byte, val encoding.TextMarshaler, opt Options) error { 105 if ret, err := val.MarshalText(); err != nil { 106 return err 107 } else { 108 if opt & NoQuoteTextMarshaler != 0 { 109 *buf = append(*buf, ret...) 110 return nil 111 } 112 return encodeString(buf, rt.Mem2Str(ret) ) 113 } 114 } 115 116 func htmlEscape(dst []byte, src []byte) []byte { 117 var sidx int 118 119 dst = append(dst, src[:0]...) // avoid check nil dst 120 sbuf := (*rt.GoSlice)(unsafe.Pointer(&src)) 121 dbuf := (*rt.GoSlice)(unsafe.Pointer(&dst)) 122 123 /* grow dst if it is shorter */ 124 if cap(dst) - len(dst) < len(src) + native.BufPaddingSize { 125 cap := len(src) * 3 / 2 + native.BufPaddingSize 126 *dbuf = growslice(typeByte, *dbuf, cap) 127 } 128 129 for sidx < sbuf.Len { 130 sp := padd(sbuf.Ptr, sidx) 131 dp := padd(dbuf.Ptr, dbuf.Len) 132 133 sn := sbuf.Len - sidx 134 dn := dbuf.Cap - dbuf.Len 135 nb := native.HTMLEscape(sp, sn, dp, &dn) 136 137 /* check for errors */ 138 if dbuf.Len += dn; nb >= 0 { 139 break 140 } 141 142 /* not enough space, grow the slice and try again */ 143 sidx += ^nb 144 *dbuf = growslice(typeByte, *dbuf, dbuf.Cap * 2) 145 } 146 return dst 147 } 148 149 var ( 150 argPtrs = []bool { true, true, true, false } 151 localPtrs = []bool{} 152 ) 153 154 var ( 155 _F_assertI2I = jit.Func(assertI2I) 156 ) 157 158 func asText(v unsafe.Pointer) (string, error) { 159 text := assertI2I(_T_encoding_TextMarshaler, *(*rt.GoIface)(v)) 160 r, e := (*(*encoding.TextMarshaler)(unsafe.Pointer(&text))).MarshalText() 161 return rt.Mem2Str(r), e 162 } 163 164 func asJson(v unsafe.Pointer) (string, error) { 165 text := assertI2I(_T_json_Marshaler, *(*rt.GoIface)(v)) 166 r, e := (*(*json.Marshaler)(unsafe.Pointer(&text))).MarshalJSON() 167 return rt.Mem2Str(r), e 168 }