Source file src/encoding/json/v2/arshal.go
1 // Copyright 2020 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build goexperiment.jsonv2 6 7 package json 8 9 import ( 10 "bytes" 11 "encoding" 12 "errors" 13 "io" 14 "reflect" 15 "sync" 16 "time" 17 18 "encoding/json/internal" 19 "encoding/json/internal/jsonflags" 20 "encoding/json/internal/jsonopts" 21 "encoding/json/jsontext" 22 ) 23 24 // Reference encoding and time packages to assist pkgsite 25 // in being able to hotlink references to those packages. 26 var ( 27 _ encoding.TextMarshaler 28 _ encoding.TextAppender 29 _ encoding.TextUnmarshaler 30 _ time.Time 31 _ time.Duration 32 ) 33 34 var ( 35 // Once a JSON object has begun processing without duplicate name verification, 36 // it does not track the history of names that have been seen so far. 37 // Reject changing the setting for the current JSON object namespace, 38 // otherwise we would be operating with inconsistent state. 39 // Note that you can change the setting before processing the start 40 // of a different JSON object. 41 // 42 // TODO: We could loosen this restriction in certain conditions. 43 // If we are already checking for duplicate names, 44 // we can momentarily disable it for the next JSON object member name. 45 // However, if we are already NOT checking for duplicate names, 46 // we cannot momentarily enable it for the next JSON object member name 47 // since we already lack prior history of JSON object names. 48 errChangingDuplicateNames = errors.New("cannot change duplicate name checks after a JSON object has already begun processing") 49 50 // The presence of invalid UTF-8 has an interesting intersection 51 // with checking for duplicate names. Due to the semantic of mangling 52 // invalid UTF-8 as the Unicode replacement character, 53 // two string keys in a Go map (both with invalid UTF-8) 54 // may encode as the same JSON string. Thus, we forbid changing of 55 // invalid UTF-8 checks in the current JSON object namespace. 56 errChangingInvalidUTF8 = errors.New("cannot change UTF-8 checks after a JSON object has already begun processing") 57 58 // TODO(https://go.dev/issue/79559): Changing whitespace currently 59 // leads to strange effects and will need more careful adjustment. 60 // For now, we just report an error. 61 errChangingWhitespace = errors.New("cannot change whitespace formatting within a MarshalEncode call") 62 ) 63 64 // export exposes internal functionality of the "jsontext" package. 65 var export = jsontext.Internal.Export(&internal.AllowInternalUse) 66 67 // Marshal serializes a Go value as a []byte according to the provided 68 // marshal and encode options (while ignoring unmarshal or decode options). 69 // It does not terminate the output with a newline. 70 // 71 // Type-specific marshal functions and methods take precedence 72 // over the default representation of a value. 73 // Functions or methods that operate on *T are only called when encoding 74 // a value of type T (by taking its address) or a non-nil value of *T. 75 // Marshal ensures that a value is always addressable 76 // (by copying the value if necessary) so that 77 // these functions and methods can be consistently called. For performance, 78 // it is recommended that Marshal be passed a non-nil pointer to the value. 79 // 80 // The input value is encoded as JSON according to the following rules: 81 // 82 // - If any type-specific functions in a [WithMarshalers] option match 83 // the value type, then those functions are called to encode the value. 84 // If all applicable functions return [errors.ErrUnsupported], 85 // then the value is encoded according to subsequent rules. 86 // 87 // - If the value type implements [MarshalerTo], 88 // then the MarshalJSONTo method is called to encode the value. 89 // If the method returns [errors.ErrUnsupported], 90 // then the input is encoded according to subsequent rules. 91 // 92 // - If the value type implements [Marshaler], 93 // then the MarshalJSON method is called to encode the value. 94 // 95 // - If the value type implements [encoding.TextAppender], 96 // then the AppendText method is called to encode the value and 97 // subsequently encode its result as a JSON string. 98 // 99 // - If the value type implements [encoding.TextMarshaler], 100 // then the MarshalText method is called to encode the value and 101 // subsequently encode its result as a JSON string. 102 // 103 // - Otherwise, the value is encoded according to the value's type 104 // as described in detail below. 105 // 106 // Most Go types have a default JSON representation as follows: 107 // 108 // - A Go boolean is encoded as a JSON boolean (e.g., true or false). 109 // 110 // - A Go string is encoded as a JSON string. 111 // 112 // - A Go []byte or [N]byte is encoded as a JSON string containing 113 // a binary value using Base 64 Encoding per RFC 4648, section 4. 114 // 115 // - A Go integer is encoded as a JSON number without fractions or exponents. 116 // If [StringifyNumbers] is specified or encoding a JSON object name, 117 // then the JSON number is encoded within a JSON string. 118 // 119 // - A Go float is encoded as a JSON number. 120 // If [StringifyNumbers] is specified or encoding a JSON object name, 121 // then the JSON number is encoded within a JSON string. 122 // Encoding a NaN or ±Inf results in a [SemanticError]. 123 // 124 // - A Go map is encoded as a JSON object, where each Go map key and value 125 // is recursively encoded as a name and value pair in the JSON object. 126 // The Go map key must encode as a JSON string, otherwise this results 127 // in a [SemanticError]. The Go map is traversed in a non-deterministic order. 128 // For deterministic encoding, consider using the [Deterministic] option. 129 // By default, a nil map is encoded as an empty JSON object, 130 // unless the [FormatNilMapAsNull] option is specified. 131 // 132 // - A Go struct is encoded as a JSON object. 133 // See the “JSON Representation of Go structs” section 134 // in the package-level documentation for more details. 135 // 136 // - A Go slice is encoded as a JSON array, where each Go slice element 137 // is recursively JSON-encoded as the elements of the JSON array. 138 // By default, a nil slice is encoded as an empty JSON array, 139 // unless the [FormatNilSliceAsNull] option is specified. 140 // 141 // - A Go array is encoded as a JSON array, where each Go array element 142 // is recursively JSON-encoded as the elements of the JSON array. 143 // The JSON array length is always identical to the Go array length. 144 // 145 // - A Go pointer is encoded as a JSON null if nil, otherwise it is 146 // the recursively JSON-encoded representation of the underlying value. 147 // 148 // - A Go interface is encoded as a JSON null if nil, otherwise it is 149 // the recursively JSON-encoded representation of the underlying value. 150 // 151 // - A Go [time.Time] is encoded as a JSON string containing the timestamp 152 // formatted in RFC 3339 with nanosecond precision. 153 // 154 // - A Go [time.Duration] currently has no default representation and 155 // results in a [SemanticError], unless the [encoding/json.FormatDurationAsNano] 156 // option is specified, in which case it is encoded as a JSON number 157 // without fractions or exponents, representing the duration in nanoseconds. 158 // 159 // - All other Go types (e.g., complex numbers, channels, and functions) 160 // have no default representation and result in a [SemanticError]. 161 // 162 // JSON cannot represent cyclic data structures and Marshal does not handle them. 163 func Marshal(in any, opts ...Options) (out []byte, err error) { 164 enc := export.GetBufferedEncoder(opts...) 165 defer export.PutBufferedEncoder(enc) 166 xe := export.Encoder(enc) 167 xe.Flags.Set(jsonflags.OmitTopLevelNewline | 1) 168 err = marshalEncode(enc, in, &xe.Struct) 169 if err != nil && xe.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { 170 return nil, internal.TransformMarshalError(in, err) 171 } 172 return bytes.Clone(xe.Buf), err 173 } 174 175 // MarshalWrite serializes a Go value into an [io.Writer] according to the provided 176 // marshal and encode options (while ignoring unmarshal or decode options). 177 // It does not terminate the output with a newline. 178 // See [Marshal] for details about the conversion of a Go value into JSON. 179 func MarshalWrite(out io.Writer, in any, opts ...Options) (err error) { 180 enc := export.GetStreamingEncoder(out, opts...) 181 defer export.PutStreamingEncoder(enc) 182 xe := export.Encoder(enc) 183 xe.Flags.Set(jsonflags.OmitTopLevelNewline | 1) 184 err = marshalEncode(enc, in, &xe.Struct) 185 if err != nil && xe.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { 186 return internal.TransformMarshalError(in, err) 187 } 188 return err 189 } 190 191 // MarshalEncode serializes a Go value into an [jsontext.Encoder] according to 192 // the provided marshal or encode options (while ignoring unmarshal or decode options). 193 // The options provided take precedence over options already applied on 194 // the [jsontext.Encoder] and only apply for the duration of the marshal call. 195 // 196 // See [Marshal] for details about the conversion of a Go value into JSON. 197 func MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) (err error) { 198 xe := export.Encoder(out) 199 if len(opts) > 0 { 200 optsOriginal := xe.Struct 201 defer func() { xe.Struct = optsOriginal }() 202 xe.Struct.Join(opts...) 203 if xe.Tokens.Last.NeedObjectName() { 204 if optsOriginal.Flags.Get(jsonflags.AllowDuplicateNames) != xe.Struct.Flags.Get(jsonflags.AllowDuplicateNames) { 205 return newMarshalErrorBefore(out, reflect.TypeOf(in), errChangingDuplicateNames) 206 } 207 if optsOriginal.Flags.Get(jsonflags.AllowInvalidUTF8) != xe.Struct.Flags.Get(jsonflags.AllowInvalidUTF8) { 208 return newMarshalErrorBefore(out, reflect.TypeOf(in), errChangingInvalidUTF8) 209 } 210 } 211 if xe.Struct.Flags.Has(jsonflags.AnyWhitespace) { 212 if xe.Struct.Flags.Get(jsonflags.Multiline) { 213 xe.Struct.InitializeMultiline() 214 } 215 if jsonopts.ChangedWhitespace(optsOriginal, xe.Struct) { 216 return newMarshalErrorBefore(out, reflect.TypeOf(in), errChangingWhitespace) 217 } 218 } 219 } 220 err = marshalEncode(out, in, &xe.Struct) 221 if err != nil && xe.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { 222 return internal.TransformMarshalError(in, err) 223 } 224 return err 225 } 226 227 func marshalEncode(out *jsontext.Encoder, in any, mo *jsonopts.Struct) (err error) { 228 v := reflect.ValueOf(in) 229 if !v.IsValid() || (v.Kind() == reflect.Pointer && v.IsNil()) { 230 return out.WriteToken(jsontext.Null) 231 } 232 // Shallow copy non-pointer values to obtain an addressable value. 233 // It is beneficial to performance to always pass pointers to avoid this. 234 forceAddr := v.Kind() != reflect.Pointer 235 if forceAddr { 236 v2 := reflect.New(v.Type()) 237 v2.Elem().Set(v) 238 v = v2 239 } 240 va := addressableValue{v.Elem(), forceAddr} // dereferenced pointer is always addressable 241 t := va.Type() 242 243 // Lookup and call the marshal function for this type. 244 marshal := lookupArshaler(t).marshal 245 if mo.Marshalers != nil { 246 marshal, _ = mo.Marshalers.(*Marshalers).lookup(marshal, t) 247 } 248 if err := marshal(out, va, mo); err != nil { 249 if !mo.Flags.Get(jsonflags.AllowDuplicateNames) { 250 export.Encoder(out).Tokens.InvalidateDisabledNamespaces() 251 } 252 return err 253 } 254 return nil 255 } 256 257 // Unmarshal decodes a []byte input into a Go value according to the provided 258 // unmarshal and decode options (while ignoring marshal or encode options). 259 // The input must be a single JSON value with optional whitespace interspersed. 260 // The output must be a non-nil pointer. 261 // 262 // Type-specific unmarshal functions and methods take precedence 263 // over the default representation of a value. 264 // Functions or methods that operate on *T are only called when decoding 265 // a value of type T (by taking its address) or a non-nil value of *T. 266 // Unmarshal ensures that a value is always addressable 267 // (by copying the value if necessary) so that 268 // these functions and methods can be consistently called. 269 // If a value must be shallow copied to call a pointer-receiver 270 // [Unmarshaler], [UnmarshalerFrom], or [encoding.TextUnmarshaler] method, 271 // then any mutations performed by the method are shallow copied back 272 // into the destination value. 273 // 274 // The input is decoded into the output according to the following rules: 275 // 276 // - If any type-specific functions in a [WithUnmarshalers] option match 277 // the value type, then those functions are called to decode the JSON 278 // value. If all applicable functions return [errors.ErrUnsupported], 279 // then the input is decoded according to subsequent rules. 280 // 281 // - If the value type implements [UnmarshalerFrom], 282 // then the UnmarshalJSONFrom method is called to decode the JSON value. 283 // If the method returns [errors.ErrUnsupported], 284 // then the input is decoded according to subsequent rules. 285 // 286 // - If the value type implements [Unmarshaler], 287 // then the UnmarshalJSON method is called to decode the JSON value. 288 // 289 // - If the value type implements [encoding.TextUnmarshaler], 290 // then the input is decoded as a JSON string and 291 // the UnmarshalText method is called with the decoded string value. 292 // This fails with a [SemanticError] if the input is not a JSON string. 293 // 294 // - Otherwise, the JSON value is decoded according to the value's type 295 // as described in detail below. 296 // 297 // Most Go types have a default JSON representation. 298 // A JSON null may be decoded into every supported Go value where 299 // it is equivalent to storing the zero value of the Go value. 300 // If the input JSON kind is not handled by the current Go value type, 301 // then this fails with a [SemanticError]. Unless otherwise specified, 302 // the decoded value replaces any pre-existing value. 303 // 304 // The representation of each type is as follows: 305 // 306 // - A Go boolean is decoded from a JSON boolean (e.g., true or false). 307 // 308 // - A Go string is decoded from a JSON string. 309 // 310 // - A Go []byte or [N]byte is decoded from a JSON string containing 311 // a binary value using Base 64 Encoding per RFC 4648, section 4. 312 // When decoding into a non-nil []byte, the slice length is reset to zero 313 // and the decoded input is appended to it. 314 // When decoding into a [N]byte, the input must decode to exactly N bytes, 315 // otherwise it fails with a [SemanticError]. 316 // 317 // - A Go integer is decoded from a JSON number. 318 // It must be decoded from a JSON string containing a JSON number 319 // if [StringifyNumbers] is specified or decoding a JSON object name. 320 // It fails with a [SemanticError] if the JSON number 321 // has a fractional or exponent component. 322 // It also fails if it overflows the representation of the Go integer type. 323 // 324 // - A Go float is decoded from a JSON number. 325 // It must be decoded from a JSON string containing a JSON number 326 // if [StringifyNumbers] is specified or decoding a JSON object name. 327 // It fails if it overflows the representation of the Go float type. 328 // Since JSON lacks a native representation for a NaN or ±Inf, 329 // such values cannot be the result of decoding. 330 // 331 // - A Go map is decoded from a JSON object, 332 // where each JSON object name and value pair is recursively decoded 333 // as the Go map key and value. Maps are not cleared. 334 // If the Go map is nil, then a new map is allocated to decode into. 335 // If the decoded key matches an existing Go map entry, the entry value 336 // is reused by decoding the JSON object value into it. 337 // 338 // - A Go struct is decoded from a JSON object. 339 // See the “JSON Representation of Go structs” section 340 // in the package-level documentation for more details. 341 // 342 // - A Go slice is decoded from a JSON array, where each JSON element 343 // is recursively decoded and appended to the Go slice. 344 // Before appending into a Go slice, a new slice is allocated if it is nil, 345 // otherwise the slice length is reset to zero. 346 // 347 // - A Go array is decoded from a JSON array, where each JSON array element 348 // is recursively decoded as each corresponding Go array element. 349 // Each Go array element is zeroed before decoding into it. 350 // It fails with a [SemanticError] if the JSON array does not contain 351 // the exact same number of elements as the Go array. 352 // 353 // - A Go pointer is decoded based on the JSON kind and underlying Go type. 354 // If the input is a JSON null, then this stores a nil pointer. 355 // Otherwise, it allocates a new underlying value if the pointer is nil, 356 // and recursively JSON decodes into the underlying value. 357 // 358 // - A Go interface is decoded based on the JSON kind and underlying Go type. 359 // If the input is a JSON null, then this stores a nil interface value. 360 // Otherwise, a nil interface value of an empty interface type is initialized 361 // with a zero Go bool, string, float64, map[string]any, or []any if the 362 // input is a JSON boolean, string, number, object, or array, respectively. 363 // If the interface value is still nil, then this fails with a [SemanticError] 364 // since decoding could not determine an appropriate Go type to decode into. 365 // For example, unmarshaling into a nil io.Reader fails since 366 // there is no concrete type to populate the interface value with. 367 // Otherwise an underlying value exists and it recursively decodes 368 // the JSON input into it. 369 // 370 // - A Go [time.Time] is decoded from a JSON string containing the time 371 // formatted in RFC 3339 with nanosecond precision. 372 // 373 // - A Go [time.Duration] currently has no default representation and 374 // results in a [SemanticError], unless the [encoding/json.FormatDurationAsNano] 375 // option is specified, in which case it is decoded as a JSON number 376 // without fractions or exponents, representing the duration in nanoseconds. 377 // 378 // - All other Go types (e.g., complex numbers, channels, and functions) 379 // have no default representation and result in a [SemanticError]. 380 // 381 // In general, unmarshaling follows merge semantics (similar to RFC 7396) 382 // where the decoded Go value replaces the destination value 383 // for any JSON kind other than an object. 384 // For JSON objects, the input object is merged into the destination value 385 // where matching object members recursively apply merge semantics. 386 func Unmarshal(in []byte, out any, opts ...Options) (err error) { 387 dec := export.GetBufferedDecoder(in, opts...) 388 defer export.PutBufferedDecoder(dec) 389 xd := export.Decoder(dec) 390 err = unmarshalDecode(dec, out, &xd.Struct, true) 391 if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { 392 return internal.TransformUnmarshalError(out, err) 393 } 394 return err 395 } 396 397 // UnmarshalRead deserializes a Go value from an [io.Reader] according to the 398 // provided unmarshal and decode options (while ignoring marshal or encode options). 399 // The input must be a single JSON value with optional whitespace interspersed. 400 // It consumes the entirety of [io.Reader] until [io.EOF] is encountered, 401 // without reporting an error for EOF. The output must be a non-nil pointer. 402 // See [Unmarshal] for details about the conversion of JSON into a Go value. 403 func UnmarshalRead(in io.Reader, out any, opts ...Options) (err error) { 404 dec := export.GetStreamingDecoder(in, opts...) 405 defer export.PutStreamingDecoder(dec) 406 xd := export.Decoder(dec) 407 err = unmarshalDecode(dec, out, &xd.Struct, true) 408 if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { 409 return internal.TransformUnmarshalError(out, err) 410 } 411 return err 412 } 413 414 // UnmarshalDecode deserializes a Go value from a [jsontext.Decoder] according to 415 // the provided unmarshal or decode options (while ignoring marshal or encode options). 416 // The options provided take precedence over options already applied on 417 // the [jsontext.Decoder] and only apply for the duration of the unmarshal call. 418 // 419 // The input may be a stream of zero or more JSON values. 420 // UnmarshalDecode unmarshals only the next JSON value in the stream. 421 // If there are no more top-level JSON values, it reports [io.EOF]. 422 // The output must be a non-nil pointer. 423 // See [Unmarshal] for details about the conversion of JSON into a Go value. 424 func UnmarshalDecode(in *jsontext.Decoder, out any, opts ...Options) (err error) { 425 xd := export.Decoder(in) 426 if len(opts) > 0 { 427 optsOriginal := xd.Struct 428 defer func() { xd.Struct = optsOriginal }() 429 xd.Struct.Join(opts...) 430 if xd.Tokens.Last.NeedObjectName() { 431 if optsOriginal.Flags.Get(jsonflags.AllowDuplicateNames) != xd.Struct.Flags.Get(jsonflags.AllowDuplicateNames) { 432 return newUnmarshalErrorBefore(in, reflect.TypeOf(out), errChangingDuplicateNames) 433 } 434 if optsOriginal.Flags.Get(jsonflags.AllowInvalidUTF8) != xd.Struct.Flags.Get(jsonflags.AllowInvalidUTF8) { 435 return newUnmarshalErrorBefore(in, reflect.TypeOf(out), errChangingInvalidUTF8) 436 } 437 } 438 } 439 err = unmarshalDecode(in, out, &xd.Struct, false) 440 if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { 441 return internal.TransformUnmarshalError(out, err) 442 } 443 return err 444 } 445 446 func unmarshalDecode(in *jsontext.Decoder, out any, uo *jsonopts.Struct, last bool) (err error) { 447 v := reflect.ValueOf(out) 448 if v.Kind() != reflect.Pointer || v.IsNil() { 449 return &SemanticError{action: "unmarshal", GoType: reflect.TypeOf(out), Err: internal.ErrNonNilReference} 450 } 451 va := addressableValue{v.Elem(), false} // dereferenced pointer is always addressable 452 t := va.Type() 453 454 // In legacy semantics, the entirety of the next JSON value 455 // was validated before attempting to unmarshal it. 456 if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { 457 if err := export.Decoder(in).CheckNextValue(last); err != nil { 458 if err == io.EOF && last { 459 offset := in.InputOffset() + int64(len(in.UnreadBuffer())) 460 return &jsontext.SyntacticError{ByteOffset: offset, Err: io.ErrUnexpectedEOF} 461 } 462 return err 463 } 464 } 465 466 // Lookup and call the unmarshal function for this type. 467 unmarshal := lookupArshaler(t).unmarshal 468 if uo.Unmarshalers != nil { 469 unmarshal, _ = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshal, t) 470 } 471 if err := unmarshal(in, va, uo); err != nil { 472 if !uo.Flags.Get(jsonflags.AllowDuplicateNames) { 473 export.Decoder(in).Tokens.InvalidateDisabledNamespaces() 474 } 475 if err == io.EOF && last { 476 offset := in.InputOffset() + int64(len(in.UnreadBuffer())) 477 return &jsontext.SyntacticError{ByteOffset: offset, Err: io.ErrUnexpectedEOF} 478 } 479 return err 480 } 481 if last { 482 return export.Decoder(in).CheckEOF() 483 } 484 return nil 485 } 486 487 // addressableValue is a reflect.Value that is guaranteed to be addressable 488 // such that calling the Addr and Set methods do not panic. 489 // 490 // There is no compile magic that enforces this property, 491 // but rather the need to construct this type makes it easier to examine each 492 // construction site to ensure that this property is upheld. 493 type addressableValue struct { 494 reflect.Value 495 496 // forcedAddr reports whether this value is addressable 497 // only through the use of [newAddressableValue]. 498 // This is only used for [jsonflags.CallMethodsWithLegacySemantics]. 499 forcedAddr bool 500 } 501 502 // newAddressableValue constructs a new addressable value of type t. 503 func newAddressableValue(t reflect.Type) addressableValue { 504 return addressableValue{reflect.New(t).Elem(), true} 505 } 506 507 // TODO: Remove *jsonopts.Struct argument from [marshaler] and [unmarshaler]. 508 // This can be directly accessed on the encoder or decoder. 509 510 // All marshal and unmarshal behavior is implemented using these signatures. 511 // The *jsonopts.Struct argument is guaranteed to be identical to or at least 512 // a strict super-set of the options in Encoder.Struct or Decoder.Struct. 513 // It is identical for Marshal, Unmarshal, MarshalWrite, and UnmarshalRead. 514 // It is a super-set for MarshalEncode and UnmarshalDecode. 515 type ( 516 marshaler = func(*jsontext.Encoder, addressableValue, *jsonopts.Struct) error 517 unmarshaler = func(*jsontext.Decoder, addressableValue, *jsonopts.Struct) error 518 ) 519 520 type arshaler struct { 521 marshal marshaler 522 unmarshal unmarshaler 523 nonDefault bool 524 } 525 526 var lookupArshalerCache sync.Map // map[reflect.Type]*arshaler 527 528 func lookupArshaler(t reflect.Type) *arshaler { 529 if v, ok := lookupArshalerCache.Load(t); ok { 530 return v.(*arshaler) 531 } 532 533 fncs := makeDefaultArshaler(t) 534 fncs = makeMethodArshaler(fncs, t) 535 fncs = makeTimeArshaler(fncs, t) 536 537 // Use the last stored so that duplicate arshalers can be garbage collected. 538 v, _ := lookupArshalerCache.LoadOrStore(t, fncs) 539 return v.(*arshaler) 540 } 541 542 var stringsPools = &sync.Pool{New: func() any { return new(stringSlice) }} 543 544 type stringSlice []string 545 546 // getStrings returns a non-nil pointer to a slice with length n. 547 func getStrings(n int) *stringSlice { 548 s := stringsPools.Get().(*stringSlice) 549 if cap(*s) < n { 550 *s = make([]string, n) 551 } 552 *s = (*s)[:n] 553 return s 554 } 555 556 func putStrings(s *stringSlice) { 557 if cap(*s) > 1<<10 { 558 *s = nil // avoid pinning arbitrarily large amounts of memory 559 } 560 clear(*s) // avoid pinning a reference to each string 561 stringsPools.Put(s) 562 } 563