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  }