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