gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

encoder_compat.go (7261B)


      1 // +build !amd64 go1.21
      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 // Options is a set of encoding options.
     31 type Options uint64
     32 
     33 const (
     34     bitSortMapKeys          = iota
     35     bitEscapeHTML          
     36     bitCompactMarshaler
     37     bitNoQuoteTextMarshaler
     38     bitNoNullSliceOrMap
     39     bitValidateString
     40 
     41     // used for recursive compile
     42     bitPointerValue = 63
     43 )
     44 
     45 const (
     46     // SortMapKeys indicates that the keys of a map needs to be sorted 
     47     // before serializing into JSON.
     48     // WARNING: This hurts performance A LOT, USE WITH CARE.
     49     SortMapKeys          Options = 1 << bitSortMapKeys
     50 
     51     // EscapeHTML indicates encoder to escape all HTML characters 
     52     // after serializing into JSON (see https://pkg.go.dev/encoding/json#HTMLEscape).
     53     // WARNING: This hurts performance A LOT, USE WITH CARE.
     54     EscapeHTML           Options = 1 << bitEscapeHTML
     55 
     56     // CompactMarshaler indicates that the output JSON from json.Marshaler 
     57     // is always compact and needs no validation 
     58     CompactMarshaler     Options = 1 << bitCompactMarshaler
     59 
     60     // NoQuoteTextMarshaler indicates that the output text from encoding.TextMarshaler 
     61     // is always escaped string and needs no quoting
     62     NoQuoteTextMarshaler Options = 1 << bitNoQuoteTextMarshaler
     63 
     64     // NoNullSliceOrMap indicates all empty Array or Object are encoded as '[]' or '{}',
     65     // instead of 'null'
     66     NoNullSliceOrMap     Options = 1 << bitNoNullSliceOrMap
     67 
     68     // ValidateString indicates that encoder should validate the input string
     69     // before encoding it into JSON.
     70     ValidateString       Options = 1 << bitValidateString
     71   
     72     // CompatibleWithStd is used to be compatible with std encoder.
     73     CompatibleWithStd Options = SortMapKeys | EscapeHTML | CompactMarshaler
     74 )
     75 
     76 // Encoder represents a specific set of encoder configurations.
     77 type Encoder struct {
     78     Opts Options
     79     prefix string
     80     indent string
     81 }
     82 
     83 // Encode returns the JSON encoding of v.
     84 func (self *Encoder) Encode(v interface{}) ([]byte, error) {
     85     if self.indent != "" || self.prefix != "" { 
     86         return EncodeIndented(v, self.prefix, self.indent, self.Opts)
     87     }
     88     return Encode(v, self.Opts)
     89 }
     90 
     91 // SortKeys enables the SortMapKeys option.
     92 func (self *Encoder) SortKeys() *Encoder {
     93     self.Opts |= SortMapKeys
     94     return self
     95 }
     96 
     97 // SetEscapeHTML specifies if option EscapeHTML opens
     98 func (self *Encoder) SetEscapeHTML(f bool) {
     99     if f {
    100         self.Opts |= EscapeHTML
    101     } else {
    102         self.Opts &= ^EscapeHTML
    103     }
    104 }
    105 
    106 // SetValidateString specifies if option ValidateString opens
    107 func (self *Encoder) SetValidateString(f bool) {
    108     if f {
    109         self.Opts |= ValidateString
    110     } else {
    111         self.Opts &= ^ValidateString
    112     }
    113 }
    114 
    115 // SetCompactMarshaler specifies if option CompactMarshaler opens
    116 func (self *Encoder) SetCompactMarshaler(f bool) {
    117     if f {
    118         self.Opts |= CompactMarshaler
    119     } else {
    120         self.Opts &= ^CompactMarshaler
    121     }
    122 }
    123 
    124 // SetNoQuoteTextMarshaler specifies if option NoQuoteTextMarshaler opens
    125 func (self *Encoder) SetNoQuoteTextMarshaler(f bool) {
    126     if f {
    127         self.Opts |= NoQuoteTextMarshaler
    128     } else {
    129         self.Opts &= ^NoQuoteTextMarshaler
    130     }
    131 }
    132 
    133 // SetIndent instructs the encoder to format each subsequent encoded
    134 // value as if indented by the package-level function EncodeIndent().
    135 // Calling SetIndent("", "") disables indentation.
    136 func (enc *Encoder) SetIndent(prefix, indent string) {
    137     enc.prefix = prefix
    138     enc.indent = indent
    139 }
    140 
    141 // Quote returns the JSON-quoted version of s.
    142 func Quote(s string) string {
    143     /* check for empty string */
    144     if s == "" {
    145         return `""`
    146     }
    147 
    148     out, _ := json.Marshal(s)
    149     return string(out)
    150 }
    151 
    152 // Encode returns the JSON encoding of val, encoded with opts.
    153 func Encode(val interface{}, opts Options) ([]byte, error) {
    154    return json.Marshal(val)
    155 }
    156 
    157 // EncodeInto is like Encode but uses a user-supplied buffer instead of allocating
    158 // a new one.
    159 func EncodeInto(buf *[]byte, val interface{}, opts Options) error {
    160    if buf == nil {
    161        panic("user-supplied buffer buf is nil")
    162    }
    163    w := bytes.NewBuffer(*buf)
    164    enc := json.NewEncoder(w)
    165    enc.SetEscapeHTML((opts & EscapeHTML) != 0)
    166    err := enc.Encode(val)
    167    *buf = w.Bytes()
    168    return err
    169 }
    170 
    171 // HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029
    172 // characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029
    173 // so that the JSON will be safe to embed inside HTML <script> tags.
    174 // For historical reasons, web browsers don't honor standard HTML
    175 // escaping within <script> tags, so an alternative JSON encoding must
    176 // be used.
    177 func HTMLEscape(dst []byte, src []byte) []byte {
    178    d := bytes.NewBuffer(dst)
    179    json.HTMLEscape(d, src)
    180    return d.Bytes()
    181 }
    182 
    183 // EncodeIndented is like Encode but applies Indent to format the output.
    184 // Each JSON element in the output will begin on a new line beginning with prefix
    185 // followed by one or more copies of indent according to the indentation nesting.
    186 func EncodeIndented(val interface{}, prefix string, indent string, opts Options) ([]byte, error) {
    187    w := bytes.NewBuffer([]byte{})
    188    enc := json.NewEncoder(w)
    189    enc.SetEscapeHTML((opts & EscapeHTML) != 0)
    190    enc.SetIndent(prefix, indent)
    191    err := enc.Encode(val)
    192    out := w.Bytes()
    193    return out, err
    194 }
    195 
    196 // Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in
    197 // order to reduce the first-hit latency.
    198 //
    199 // Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is
    200 // a compile option to set the depth of recursive compile for the nested struct type.
    201 func Pretouch(vt reflect.Type, opts ...option.CompileOption) error {
    202    return nil
    203 }
    204 
    205 // Valid validates json and returns first non-blank character position,
    206 // if it is only one valid json value.
    207 // Otherwise returns invalid character position using start.
    208 //
    209 // Note: it does not check for the invalid UTF-8 characters.
    210 func Valid(data []byte) (ok bool, start int) {
    211    return json.Valid(data), 0
    212 }
    213 
    214 // StreamEncoder uses io.Writer as 
    215 type StreamEncoder struct {
    216    w io.Writer
    217    Encoder
    218 }
    219 
    220 // NewStreamEncoder adapts to encoding/json.NewDecoder API.
    221 //
    222 // NewStreamEncoder returns a new encoder that write to w.
    223 func NewStreamEncoder(w io.Writer) *StreamEncoder {
    224    return &StreamEncoder{w: w}
    225 }
    226 
    227 // Encode encodes interface{} as JSON to io.Writer
    228 func (enc *StreamEncoder) Encode(val interface{}) (err error) {
    229    jenc := json.NewEncoder(enc.w)
    230    jenc.SetEscapeHTML((enc.Opts & EscapeHTML) != 0)
    231    jenc.SetIndent(enc.prefix, enc.indent)
    232    err = jenc.Encode(val)
    233    return err
    234 }