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 }