github.com/bytedance/sonic@v1.11.7-0.20240517092252-d2edb31b167b/encoder/encoder_compat.go (about)

     1  // +build !amd64 !go1.16 go1.23
     2  
     3  /*
     4  * Copyright 2023 ByteDance Inc.
     5  *
     6  * Licensed under the Apache License, Version 2.0 (the "License");
     7  * you may not use this file except in compliance with the License.
     8  * You may obtain a copy of the License at
     9  *
    10  *     http://www.apache.org/licenses/LICENSE-2.0
    11  *
    12  * Unless required by applicable law or agreed to in writing, software
    13  * distributed under the License is distributed on an "AS IS" BASIS,
    14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15  * See the License for the specific language governing permissions and
    16  * limitations under the License.
    17  */
    18  
    19  package encoder
    20  
    21  import (
    22     `io`
    23      `bytes`
    24      `encoding/json`
    25      `reflect`
    26  
    27      `github.com/bytedance/sonic/option`
    28  )
    29  
    30  func init() {
    31      println("WARNING:(encoder) sonic only supports Go1.16~1.22 && CPU amd64, but your environment is not suitable")
    32  }
    33  
    34  // EnableFallback indicates if encoder use fallback
    35  const EnableFallback = true
    36  
    37  // Options is a set of encoding options.
    38  type Options uint64
    39  
    40  const (
    41      bitSortMapKeys          = iota
    42      bitEscapeHTML          
    43      bitCompactMarshaler
    44      bitNoQuoteTextMarshaler
    45      bitNoNullSliceOrMap
    46      bitValidateString
    47      bitNoValidateJSONMarshaler
    48      bitNoEncoderNewline
    49  
    50      // used for recursive compile
    51      bitPointerValue = 63
    52  )
    53  
    54  const (
    55      // SortMapKeys indicates that the keys of a map needs to be sorted 
    56      // before serializing into JSON.
    57      // WARNING: This hurts performance A LOT, USE WITH CARE.
    58      SortMapKeys          Options = 1 << bitSortMapKeys
    59  
    60      // EscapeHTML indicates encoder to escape all HTML characters 
    61      // after serializing into JSON (see https://pkg.go.dev/encoding/json#HTMLEscape).
    62      // WARNING: This hurts performance A LOT, USE WITH CARE.
    63      EscapeHTML           Options = 1 << bitEscapeHTML
    64  
    65      // CompactMarshaler indicates that the output JSON from json.Marshaler 
    66      // is always compact and needs no validation 
    67      CompactMarshaler     Options = 1 << bitCompactMarshaler
    68  
    69      // NoQuoteTextMarshaler indicates that the output text from encoding.TextMarshaler 
    70      // is always escaped string and needs no quoting
    71      NoQuoteTextMarshaler Options = 1 << bitNoQuoteTextMarshaler
    72  
    73      // NoNullSliceOrMap indicates all empty Array or Object are encoded as '[]' or '{}',
    74      // instead of 'null'
    75      NoNullSliceOrMap     Options = 1 << bitNoNullSliceOrMap
    76  
    77      // ValidateString indicates that encoder should validate the input string
    78      // before encoding it into JSON.
    79      ValidateString       Options = 1 << bitValidateString
    80  
    81      // NoValidateJSONMarshaler indicates that the encoder should not validate the output string
    82      // after encoding the JSONMarshaler to JSON.
    83      NoValidateJSONMarshaler Options = 1 << bitNoValidateJSONMarshaler
    84  
    85      // NoEncoderNewline indicates that the encoder should not add a newline after every message
    86      NoEncoderNewline Options = 1 << bitNoEncoderNewline
    87    
    88      // CompatibleWithStd is used to be compatible with std encoder.
    89      CompatibleWithStd Options = SortMapKeys | EscapeHTML | CompactMarshaler
    90  )
    91  
    92  // Encoder represents a specific set of encoder configurations.
    93  type Encoder struct {
    94      Opts Options
    95      prefix string
    96      indent string
    97  }
    98  
    99  // Encode returns the JSON encoding of v.
   100  func (self *Encoder) Encode(v interface{}) ([]byte, error) {
   101      if self.indent != "" || self.prefix != "" { 
   102          return EncodeIndented(v, self.prefix, self.indent, self.Opts)
   103      }
   104      return Encode(v, self.Opts)
   105  }
   106  
   107  // SortKeys enables the SortMapKeys option.
   108  func (self *Encoder) SortKeys() *Encoder {
   109      self.Opts |= SortMapKeys
   110      return self
   111  }
   112  
   113  // SetEscapeHTML specifies if option EscapeHTML opens
   114  func (self *Encoder) SetEscapeHTML(f bool) {
   115      if f {
   116          self.Opts |= EscapeHTML
   117      } else {
   118          self.Opts &= ^EscapeHTML
   119      }
   120  }
   121  
   122  // SetValidateString specifies if option ValidateString opens
   123  func (self *Encoder) SetValidateString(f bool) {
   124      if f {
   125          self.Opts |= ValidateString
   126      } else {
   127          self.Opts &= ^ValidateString
   128      }
   129  }
   130  
   131  // SetNoValidateJSONMarshaler specifies if option NoValidateJSONMarshaler opens
   132  func (self *Encoder) SetNoValidateJSONMarshaler(f bool) {
   133      if f {
   134          self.Opts |= NoValidateJSONMarshaler
   135      } else {
   136          self.Opts &= ^NoValidateJSONMarshaler
   137      }
   138  }
   139  
   140  // SetNoEncoderNewline specifies if option NoEncoderNewline opens
   141  func (self *Encoder) SetNoEncoderNewline(f bool) {
   142      if f {
   143          self.Opts |= NoEncoderNewline
   144      } else {
   145          self.Opts &= ^NoEncoderNewline
   146      }
   147  }
   148  
   149  // SetCompactMarshaler specifies if option CompactMarshaler opens
   150  func (self *Encoder) SetCompactMarshaler(f bool) {
   151      if f {
   152          self.Opts |= CompactMarshaler
   153      } else {
   154          self.Opts &= ^CompactMarshaler
   155      }
   156  }
   157  
   158  // SetNoQuoteTextMarshaler specifies if option NoQuoteTextMarshaler opens
   159  func (self *Encoder) SetNoQuoteTextMarshaler(f bool) {
   160      if f {
   161          self.Opts |= NoQuoteTextMarshaler
   162      } else {
   163          self.Opts &= ^NoQuoteTextMarshaler
   164      }
   165  }
   166  
   167  // SetIndent instructs the encoder to format each subsequent encoded
   168  // value as if indented by the package-level function EncodeIndent().
   169  // Calling SetIndent("", "") disables indentation.
   170  func (enc *Encoder) SetIndent(prefix, indent string) {
   171      enc.prefix = prefix
   172      enc.indent = indent
   173  }
   174  
   175  // Quote returns the JSON-quoted version of s.
   176  func Quote(s string) string {
   177      /* check for empty string */
   178      if s == "" {
   179          return `""`
   180      }
   181  
   182      out, _ := json.Marshal(s)
   183      return string(out)
   184  }
   185  
   186  // Encode returns the JSON encoding of val, encoded with opts.
   187  func Encode(val interface{}, opts Options) ([]byte, error) {
   188     return json.Marshal(val)
   189  }
   190  
   191  // EncodeInto is like Encode but uses a user-supplied buffer instead of allocating
   192  // a new one.
   193  func EncodeInto(buf *[]byte, val interface{}, opts Options) error {
   194      if buf == nil {
   195          panic("user-supplied buffer buf is nil")
   196      }
   197      w := bytes.NewBuffer(*buf)
   198      enc := json.NewEncoder(w)
   199      enc.SetEscapeHTML((opts & EscapeHTML) != 0)
   200      err := enc.Encode(val)
   201      *buf = w.Bytes()
   202      l := len(*buf)
   203      if l > 0 && (opts & NoEncoderNewline != 0) && (*buf)[l-1] == '\n' {
   204          *buf = (*buf)[:l-1]
   205      }
   206      return err
   207  }
   208  
   209  // HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029
   210  // characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029
   211  // so that the JSON will be safe to embed inside HTML <script> tags.
   212  // For historical reasons, web browsers don't honor standard HTML
   213  // escaping within <script> tags, so an alternative JSON encoding must
   214  // be used.
   215  func HTMLEscape(dst []byte, src []byte) []byte {
   216     d := bytes.NewBuffer(dst)
   217     json.HTMLEscape(d, src)
   218     return d.Bytes()
   219  }
   220  
   221  // EncodeIndented is like Encode but applies Indent to format the output.
   222  // Each JSON element in the output will begin on a new line beginning with prefix
   223  // followed by one or more copies of indent according to the indentation nesting.
   224  func EncodeIndented(val interface{}, prefix string, indent string, opts Options) ([]byte, error) {
   225     w := bytes.NewBuffer([]byte{})
   226     enc := json.NewEncoder(w)
   227     enc.SetEscapeHTML((opts & EscapeHTML) != 0)
   228     enc.SetIndent(prefix, indent)
   229     err := enc.Encode(val)
   230     out := w.Bytes()
   231     return out, err
   232  }
   233  
   234  // Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in
   235  // order to reduce the first-hit latency.
   236  //
   237  // Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is
   238  // a compile option to set the depth of recursive compile for the nested struct type.
   239  func Pretouch(vt reflect.Type, opts ...option.CompileOption) error {
   240     return nil
   241  }
   242  
   243  // Valid validates json and returns first non-blank character position,
   244  // if it is only one valid json value.
   245  // Otherwise returns invalid character position using start.
   246  //
   247  // Note: it does not check for the invalid UTF-8 characters.
   248  func Valid(data []byte) (ok bool, start int) {
   249     return json.Valid(data), 0
   250  }
   251  
   252  // StreamEncoder uses io.Writer as 
   253  type StreamEncoder = json.Encoder
   254  
   255  // NewStreamEncoder adapts to encoding/json.NewDecoder API.
   256  //
   257  // NewStreamEncoder returns a new encoder that write to w.
   258  func NewStreamEncoder(w io.Writer) *StreamEncoder {
   259     return json.NewEncoder(w)
   260  }
   261