github.com/goshafaq/sonic@v0.0.0-20231026082336-871835fb94c6/internal/encoder/primitives.go (about) 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/goshafaq/sonic/internal/jit" 25 "github.com/goshafaq/sonic/internal/native" 26 "github.com/goshafaq/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 opt&NoValidateJSONMarshaler == 0 { 97 if ok, s := Valid(ret); !ok { 98 return error_marshaler(ret, s) 99 } 100 } 101 *buf = append(*buf, ret...) 102 return nil 103 } 104 } 105 106 func encodeTextMarshaler(buf *[]byte, val encoding.TextMarshaler, opt Options) error { 107 if ret, err := val.MarshalText(); err != nil { 108 return err 109 } else { 110 if opt&NoQuoteTextMarshaler != 0 { 111 *buf = append(*buf, ret...) 112 return nil 113 } 114 return encodeString(buf, rt.Mem2Str(ret)) 115 } 116 } 117 118 func htmlEscape(dst []byte, src []byte) []byte { 119 var sidx int 120 121 dst = append(dst, src[:0]...) // avoid check nil dst 122 sbuf := (*rt.GoSlice)(unsafe.Pointer(&src)) 123 dbuf := (*rt.GoSlice)(unsafe.Pointer(&dst)) 124 125 /* grow dst if it is shorter */ 126 if cap(dst)-len(dst) < len(src)+native.BufPaddingSize { 127 cap := len(src)*3/2 + native.BufPaddingSize 128 *dbuf = growslice(typeByte, *dbuf, cap) 129 } 130 131 for sidx < sbuf.Len { 132 sp := padd(sbuf.Ptr, sidx) 133 dp := padd(dbuf.Ptr, dbuf.Len) 134 135 sn := sbuf.Len - sidx 136 dn := dbuf.Cap - dbuf.Len 137 nb := native.HTMLEscape(sp, sn, dp, &dn) 138 139 /* check for errors */ 140 if dbuf.Len += dn; nb >= 0 { 141 break 142 } 143 144 /* not enough space, grow the slice and try again */ 145 sidx += ^nb 146 *dbuf = growslice(typeByte, *dbuf, dbuf.Cap*2) 147 } 148 return dst 149 } 150 151 var ( 152 argPtrs = []bool{true, true, true, false} 153 localPtrs = []bool{} 154 ) 155 156 var ( 157 _F_assertI2I = jit.Func(assertI2I) 158 ) 159 160 func asText(v unsafe.Pointer) (string, error) { 161 text := assertI2I(_T_encoding_TextMarshaler, *(*rt.GoIface)(v)) 162 r, e := (*(*encoding.TextMarshaler)(unsafe.Pointer(&text))).MarshalText() 163 return rt.Mem2Str(r), e 164 } 165 166 func asJson(v unsafe.Pointer) (string, error) { 167 text := assertI2I(_T_json_Marshaler, *(*rt.GoIface)(v)) 168 r, e := (*(*json.Marshaler)(unsafe.Pointer(&text))).MarshalJSON() 169 return rt.Mem2Str(r), e 170 }