github.com/wI2L/jettison@v0.7.5-0.20230106001914-c70014c6417a/json.go (about)

     1  package jettison
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"reflect"
     7  	"runtime"
     8  )
     9  
    10  // AppendMarshaler is a variant of the json.Marshaler
    11  // interface, implemented by types that can append a
    12  // valid and compact JSON representation of themselves
    13  // to a buffer. If a type implements both interfaces,
    14  // this one will be used in priority by the package.
    15  type AppendMarshaler interface {
    16  	AppendJSON([]byte) ([]byte, error)
    17  }
    18  
    19  // AppendMarshalerCtx is similar to AppendMarshaler,
    20  // but the method implemented also takes a context.
    21  // The use case for this interface is to dynamically
    22  // control the marshaling of the type implementing it
    23  // through the values encapsulated by the context,
    24  // that may be provided at runtime using WithContext.
    25  type AppendMarshalerCtx interface {
    26  	AppendJSONContext(context.Context, []byte) ([]byte, error)
    27  }
    28  
    29  const (
    30  	marshalerJSON          = "MarshalJSON"
    31  	marshalerText          = "MarshalText"
    32  	marshalerAppendJSONCtx = "AppendJSONContext"
    33  	marshalerAppendJSON    = "AppendJSON"
    34  )
    35  
    36  // MarshalerError represents an error from calling
    37  // the methods MarshalJSON or MarshalText.
    38  type MarshalerError struct {
    39  	Type     reflect.Type
    40  	Err      error
    41  	funcName string
    42  }
    43  
    44  // Error implements the builtin error interface.
    45  func (e *MarshalerError) Error() string {
    46  	return fmt.Sprintf("json: error calling %s for type %s: %s",
    47  		e.funcName, e.Type, e.Err.Error())
    48  }
    49  
    50  // Unwrap returns the error wrapped by e.
    51  // This doesn't implement a public interface, but
    52  // allow to use the errors.Unwrap function released
    53  // in Go1.13 with a MarshalerError.
    54  func (e *MarshalerError) Unwrap() error {
    55  	return e.Err
    56  }
    57  
    58  // UnsupportedTypeError is the error returned
    59  // by Marshal when attempting to encode an
    60  // unsupported value type.
    61  type UnsupportedTypeError struct {
    62  	Type reflect.Type
    63  }
    64  
    65  // Error implements the bultin error interface.
    66  func (e *UnsupportedTypeError) Error() string {
    67  	return fmt.Sprintf("json: unsupported type: %s", e.Type)
    68  }
    69  
    70  // UnsupportedValueError is the error returned
    71  // by Marshal when attempting to encode an
    72  // unsupported value.
    73  type UnsupportedValueError struct {
    74  	Value reflect.Value
    75  	Str   string
    76  }
    77  
    78  // Error implements the builtin error interface.
    79  func (e *UnsupportedValueError) Error() string {
    80  	return fmt.Sprintf("json: unsupported value: %s", e.Str)
    81  }
    82  
    83  // A SyntaxError is a description of a JSON syntax error.
    84  // Unlike its equivalent in the encoding/json package, the
    85  // Error method implemented does not return a meaningful
    86  // message, and the Offset field is always zero.
    87  // It is present merely for consistency.
    88  type SyntaxError struct {
    89  	msg    string
    90  	Offset int64
    91  }
    92  
    93  // Error implements the builtin error interface.
    94  func (e *SyntaxError) Error() string { return e.msg }
    95  
    96  // InvalidOptionError is the error returned by
    97  // MarshalOpts when one of the given options is
    98  // invalid.
    99  type InvalidOptionError struct {
   100  	Err error
   101  }
   102  
   103  // Error implements the builtin error interface.
   104  func (e *InvalidOptionError) Error() string {
   105  	return fmt.Sprintf("json: invalid option: %s", e.Err.Error())
   106  }
   107  
   108  // Marshal returns the JSON encoding of v.
   109  // The full documentation can be found at
   110  // https://golang.org/pkg/encoding/json/#Marshal.
   111  func Marshal(v interface{}) ([]byte, error) {
   112  	if v == nil {
   113  		return []byte("null"), nil
   114  	}
   115  	return marshalJSON(v, defaultEncOpts())
   116  }
   117  
   118  // Append is similar to Marshal but appends the JSON
   119  // representation of v to dst instead of returning a
   120  // new allocated slice.
   121  func Append(dst []byte, v interface{}) ([]byte, error) {
   122  	if v == nil {
   123  		return append(dst, "null"...), nil
   124  	}
   125  	return appendJSON(dst, v, defaultEncOpts())
   126  }
   127  
   128  // MarshalOpts is similar to Marshal, but also accepts
   129  // a list of options to configure the encoding behavior.
   130  func MarshalOpts(v interface{}, opts ...Option) ([]byte, error) {
   131  	if v == nil {
   132  		return []byte("null"), nil
   133  	}
   134  	eo := defaultEncOpts()
   135  
   136  	if len(opts) != 0 {
   137  		(&eo).apply(opts...)
   138  		if err := eo.validate(); err != nil {
   139  			return nil, &InvalidOptionError{err}
   140  		}
   141  	}
   142  	return marshalJSON(v, eo)
   143  }
   144  
   145  // AppendOpts is similar to Append, but also accepts
   146  // a list of options to configure the encoding behavior.
   147  func AppendOpts(dst []byte, v interface{}, opts ...Option) ([]byte, error) {
   148  	if v == nil {
   149  		return append(dst, "null"...), nil
   150  	}
   151  	eo := defaultEncOpts()
   152  
   153  	if len(opts) != 0 {
   154  		(&eo).apply(opts...)
   155  		if err := eo.validate(); err != nil {
   156  			return nil, &InvalidOptionError{err}
   157  		}
   158  	}
   159  	return appendJSON(dst, v, eo)
   160  }
   161  
   162  func marshalJSON(v interface{}, opts encOpts) ([]byte, error) {
   163  	ins := cachedInstr(reflect.TypeOf(v))
   164  	buf := cachedBuffer()
   165  
   166  	var err error
   167  	buf.B, err = ins(unpackEface(v).word, buf.B, opts)
   168  
   169  	// Ensure that v is reachable until
   170  	// the instruction has returned.
   171  	runtime.KeepAlive(v)
   172  
   173  	var b []byte
   174  	if err == nil {
   175  		// Make a copy of the buffer's content
   176  		// before its returned to the pool.
   177  		b = make([]byte, len(buf.B))
   178  		copy(b, buf.B)
   179  	}
   180  	bufferPool.Put(buf)
   181  
   182  	return b, err
   183  }
   184  
   185  func appendJSON(dst []byte, v interface{}, opts encOpts) ([]byte, error) {
   186  	ins := cachedInstr(reflect.TypeOf(v))
   187  	var err error
   188  	dst, err = ins(unpackEface(v).word, dst, opts)
   189  	runtime.KeepAlive(v)
   190  
   191  	return dst, err
   192  }