github.com/bytedance/sonic@v1.11.7-0.20240517092252-d2edb31b167b/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/bytedance/sonic/internal/jit`
    25      `github.com/bytedance/sonic/internal/native`
    26      `github.com/bytedance/sonic/internal/native/types`
    27      `github.com/bytedance/sonic/internal/rt`
    28  )
    29  
    30  /** Encoder Primitives **/
    31  
    32  func encodeNil(rb *[]byte) error {
    33      *rb = append(*rb, 'n', 'u', 'l', 'l')
    34      return nil
    35  }
    36  
    37  func encodeString(buf *[]byte, val string) error {
    38      var sidx int
    39      var pbuf *rt.GoSlice
    40      var pstr *rt.GoString
    41  
    42      /* opening quote */
    43      *buf = append(*buf, '"')
    44      pbuf = (*rt.GoSlice)(unsafe.Pointer(buf))
    45      pstr = (*rt.GoString)(unsafe.Pointer(&val))
    46  
    47      /* encode with native library */
    48      for sidx < pstr.Len {
    49          sn := pstr.Len - sidx
    50          dn := pbuf.Cap - pbuf.Len
    51          sp := padd(pstr.Ptr, sidx)
    52          dp := padd(pbuf.Ptr, pbuf.Len)
    53          nb := native.Quote(sp, sn, dp, &dn, 0)
    54  
    55          /* check for errors */
    56          if pbuf.Len += dn; nb >= 0 {
    57              break
    58          }
    59  
    60          /* not enough space, grow the slice and try again */
    61          sidx += ^nb
    62          *pbuf = rt.GrowSlice(rt.UnpackType(byteType), *pbuf, pbuf.Cap * 2)
    63      }
    64  
    65      /* closing quote */
    66      *buf = append(*buf, '"')
    67      return nil
    68  }
    69  
    70  func encodeTypedPointer(buf *[]byte, vt *rt.GoType, vp *unsafe.Pointer, sb *_Stack, fv uint64) error {
    71      if vt == nil {
    72          return encodeNil(buf)
    73      } else if fn, err := findOrCompile(vt, (fv&(1<<bitPointerValue)) != 0); err != nil {
    74          return err
    75      } else if vt.Indirect() {
    76          rt.MoreStack(_FP_size + native.MaxFrameSize)
    77          err := fn(buf, *vp, sb, fv)
    78          return err
    79      } else {
    80          rt.MoreStack(_FP_size + native.MaxFrameSize)
    81          err := fn(buf, unsafe.Pointer(vp), sb, fv)
    82          return err
    83      }
    84  }
    85  
    86  func encodeJsonMarshaler(buf *[]byte, val json.Marshaler, opt Options) error {
    87      if ret, err := val.MarshalJSON(); err != nil {
    88          return err
    89      } else {
    90          if opt & CompactMarshaler != 0 {
    91              return compact(buf, ret)
    92          }
    93          if opt & NoValidateJSONMarshaler == 0 {
    94              if ok, s := Valid(ret); !ok {
    95                  return error_marshaler(ret, s)
    96              }
    97          }
    98          *buf = append(*buf, ret...)
    99          return nil
   100      }
   101  }
   102  
   103  func encodeTextMarshaler(buf *[]byte, val encoding.TextMarshaler, opt Options) error {
   104      if ret, err := val.MarshalText(); err != nil {
   105          return err
   106      } else {
   107          if opt & NoQuoteTextMarshaler != 0 {
   108              *buf = append(*buf, ret...)
   109              return nil
   110          }
   111          return encodeString(buf, rt.Mem2Str(ret) )
   112      }
   113  }
   114  
   115  func htmlEscape(dst []byte, src []byte) []byte {
   116      var sidx int
   117  
   118      dst  = append(dst, src[:0]...) // avoid check nil dst
   119      sbuf := (*rt.GoSlice)(unsafe.Pointer(&src))
   120      dbuf := (*rt.GoSlice)(unsafe.Pointer(&dst))
   121  
   122      /* grow dst if it is shorter */
   123      if cap(dst) - len(dst) < len(src) + types.BufPaddingSize {
   124          cap :=  len(src) * 3 / 2 + types.BufPaddingSize
   125          *dbuf = rt.GrowSlice(typeByte, *dbuf, cap)
   126      }
   127  
   128      for sidx < sbuf.Len {
   129          sp := padd(sbuf.Ptr, sidx)
   130          dp := padd(dbuf.Ptr, dbuf.Len)
   131  
   132          sn := sbuf.Len - sidx
   133          dn := dbuf.Cap - dbuf.Len
   134          nb := native.HTMLEscape(sp, sn, dp, &dn)
   135  
   136          /* check for errors */
   137          if dbuf.Len += dn; nb >= 0 {
   138              break
   139          }
   140  
   141          /* not enough space, grow the slice and try again */
   142          sidx += ^nb
   143          *dbuf = rt.GrowSlice(typeByte, *dbuf, dbuf.Cap * 2)
   144      }
   145      return dst
   146  }
   147  
   148  var (
   149      argPtrs   = []bool { true, true, true, false }
   150      localPtrs = []bool{}
   151  )
   152  
   153  var (
   154      _F_assertI2I = jit.Func(rt.AssertI2I2)
   155  )
   156  
   157  func asText(v unsafe.Pointer) (string, error) {
   158      text := rt.AssertI2I2(_T_encoding_TextMarshaler, *(*rt.GoIface)(v))
   159      r, e := (*(*encoding.TextMarshaler)(unsafe.Pointer(&text))).MarshalText()
   160      return rt.Mem2Str(r), e
   161  }
   162  
   163  func asJson(v unsafe.Pointer) (string, error) {
   164      text := rt.AssertI2I2(_T_json_Marshaler, *(*rt.GoIface)(v))
   165      r, e := (*(*json.Marshaler)(unsafe.Pointer(&text))).MarshalJSON()
   166      return rt.Mem2Str(r), e
   167  }