github.com/goshafaq/sonic@v0.0.0-20231026082336-871835fb94c6/sonic.go (about)

     1  //go:build amd64 && go1.16 && !go1.22
     2  // +build amd64,go1.16,!go1.22
     3  
     4  /*
     5   * Copyright 2021 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  //go:generate make
    21  package sonic
    22  
    23  import (
    24  	"io"
    25  	"reflect"
    26  
    27  	"github.com/goshafaq/sonic/decoder"
    28  	"github.com/goshafaq/sonic/encoder"
    29  	"github.com/goshafaq/sonic/internal/rt"
    30  	"github.com/goshafaq/sonic/option"
    31  )
    32  
    33  type frozenConfig struct {
    34  	Config
    35  	encoderOpts encoder.Options
    36  	decoderOpts decoder.Options
    37  }
    38  
    39  // Froze convert the Config to API
    40  func (cfg Config) Froze() API {
    41  	api := &frozenConfig{Config: cfg}
    42  
    43  	// configure encoder options:
    44  	if cfg.EscapeHTML {
    45  		api.encoderOpts |= encoder.EscapeHTML
    46  	}
    47  	if cfg.SortMapKeys {
    48  		api.encoderOpts |= encoder.SortMapKeys
    49  	}
    50  	if cfg.CompactMarshaler {
    51  		api.encoderOpts |= encoder.CompactMarshaler
    52  	}
    53  	if cfg.NoQuoteTextMarshaler {
    54  		api.encoderOpts |= encoder.NoQuoteTextMarshaler
    55  	}
    56  	if cfg.NoNullSliceOrMap {
    57  		api.encoderOpts |= encoder.NoNullSliceOrMap
    58  	}
    59  	if cfg.ValidateString {
    60  		api.encoderOpts |= encoder.ValidateString
    61  	}
    62  	if cfg.NoValidateJSONMarshaler {
    63  		api.encoderOpts |= encoder.NoValidateJSONMarshaler
    64  	}
    65  
    66  	// configure decoder options:
    67  	if cfg.UseInt64 {
    68  		api.decoderOpts |= decoder.OptionUseInt64
    69  	}
    70  	if cfg.UseNumber {
    71  		api.decoderOpts |= decoder.OptionUseNumber
    72  	}
    73  	if cfg.DisallowUnknownFields {
    74  		api.decoderOpts |= decoder.OptionDisableUnknown
    75  	}
    76  	if cfg.CopyString {
    77  		api.decoderOpts |= decoder.OptionCopyString
    78  	}
    79  	if cfg.ValidateString {
    80  		api.decoderOpts |= decoder.OptionValidateString
    81  	}
    82  	return api
    83  }
    84  
    85  // Marshal is implemented by sonic
    86  func (cfg frozenConfig) Marshal(val interface{}) ([]byte, error) {
    87  	return encoder.Encode(val, cfg.encoderOpts)
    88  }
    89  
    90  // MarshalToString is implemented by sonic
    91  func (cfg frozenConfig) MarshalToString(val interface{}) (string, error) {
    92  	buf, err := encoder.Encode(val, cfg.encoderOpts)
    93  	return rt.Mem2Str(buf), err
    94  }
    95  
    96  // MarshalIndent is implemented by sonic
    97  func (cfg frozenConfig) MarshalIndent(val interface{}, prefix, indent string) ([]byte, error) {
    98  	return encoder.EncodeIndented(val, prefix, indent, cfg.encoderOpts)
    99  }
   100  
   101  // UnmarshalFromString is implemented by sonic
   102  func (cfg frozenConfig) UnmarshalFromString(buf string, val interface{}) error {
   103  	dec := decoder.NewDecoder(buf)
   104  	dec.SetOptions(cfg.decoderOpts)
   105  	err := dec.Decode(val)
   106  
   107  	/* check for errors */
   108  	if err != nil {
   109  		return err
   110  	}
   111  
   112  	return dec.CheckTrailings()
   113  }
   114  
   115  // Unmarshal is implemented by sonic
   116  func (cfg frozenConfig) Unmarshal(buf []byte, val interface{}) error {
   117  	return cfg.UnmarshalFromString(string(buf), val)
   118  }
   119  
   120  // NewEncoder is implemented by sonic
   121  func (cfg frozenConfig) NewEncoder(writer io.Writer) Encoder {
   122  	enc := encoder.NewStreamEncoder(writer)
   123  	enc.Opts = cfg.encoderOpts
   124  	return enc
   125  }
   126  
   127  // NewDecoder is implemented by sonic
   128  func (cfg frozenConfig) NewDecoder(reader io.Reader) Decoder {
   129  	dec := decoder.NewStreamDecoder(reader)
   130  	dec.SetOptions(cfg.decoderOpts)
   131  	return dec
   132  }
   133  
   134  // Valid is implemented by sonic
   135  func (cfg frozenConfig) Valid(data []byte) bool {
   136  	ok, _ := encoder.Valid(data)
   137  	return ok
   138  }
   139  
   140  // Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in
   141  // order to reduce the first-hit latency.
   142  //
   143  // Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is
   144  // a compile option to set the depth of recursive compile for the nested struct type.
   145  func Pretouch(vt reflect.Type, opts ...option.CompileOption) error {
   146  	if err := encoder.Pretouch(vt, opts...); err != nil {
   147  		return err
   148  	}
   149  	if err := decoder.Pretouch(vt, opts...); err != nil {
   150  		return err
   151  	}
   152  	// to pretouch the corresponding pointer type as well
   153  	if vt.Kind() == reflect.Ptr {
   154  		vt = vt.Elem()
   155  	} else {
   156  		vt = reflect.PtrTo(vt)
   157  	}
   158  	if err := encoder.Pretouch(vt, opts...); err != nil {
   159  		return err
   160  	}
   161  	if err := decoder.Pretouch(vt, opts...); err != nil {
   162  		return err
   163  	}
   164  	return nil
   165  }