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 // Passing cyclic structures will result in an error. 164 func Marshal(in any, opts ...Options) (out []byte, err error) { 165 enc := export.GetBufferedEncoder(opts...) 166 defer export.PutBufferedEncoder(enc) 167 xe := export.Encoder(enc) 168 xe.Flags.Set(jsonflags.OmitTopLevelNewline | 1) 169 err = marshalEncode(enc, in, &xe.Struct) 170 if err != nil && xe.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { 171 return nil, internal.TransformMarshalError(in, err) 172 } 173 return bytes.Clone(xe.Buf), err 174 } 175 176 // MarshalWrite serializes a Go value into an [io.Writer] according to the provided 177 // marshal and encode options (while ignoring unmarshal or decode options). 178 // It does not terminate the output with a newline. 179 // See [Marshal] for details about the conversion of a Go value into JSON. 180 func MarshalWrite(out io.Writer, in any, opts ...Options) (err error) { 181 enc := export.GetStreamingEncoder(out, opts...) 182 defer export.PutStreamingEncoder(enc) 183 xe := export.Encoder(enc) 184 xe.Flags.Set(jsonflags.OmitTopLevelNewline | 1) 185 err = marshalEncode(enc, in, &xe.Struct) 186 if err != nil && xe.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { 187 return internal.TransformMarshalError(in, err) 188 } 189 return err 190 } 191 192 // MarshalEncode serializes a Go value into an [jsontext.Encoder] according to 193 // the provided marshal or encode options (while ignoring unmarshal or decode options). 194 // The options provided take precedence over options already applied on 195 // the [jsontext.Encoder] and only apply for the duration of the marshal call. 196 // 197 // See [Marshal] for details about the conversion of a Go value into JSON. 198 func MarshalEncode(out *jsontext.Encoder, in any, opts ...Options) (err error) { 199 xe := export.Encoder(out) 200 if len(opts) > 0 { 201 optsOriginal := xe.Struct 202 defer func() { xe.Struct = optsOriginal }() 203 xe.Struct.Join(opts...) 204 if xe.Tokens.Last.NeedObjectName() { 205 if optsOriginal.Flags.Get(jsonflags.AllowDuplicateNames) != xe.Struct.Flags.Get(jsonflags.AllowDuplicateNames) { 206 return newMarshalErrorBefore(out, reflect.TypeOf(in), errChangingDuplicateNames) 207 } 208 if optsOriginal.Flags.Get(jsonflags.AllowInvalidUTF8) != xe.Struct.Flags.Get(jsonflags.AllowInvalidUTF8) { 209 return newMarshalErrorBefore(out, reflect.TypeOf(in), errChangingInvalidUTF8) 210 } 211 } 212 if xe.Struct.Flags.Has(jsonflags.AnyWhitespace) { 213 if xe.Struct.Flags.Get(jsonflags.Multiline) { 214 xe.Struct.InitializeMultiline() 215 } 216 if jsonopts.ChangedWhitespace(optsOriginal, xe.Struct) { 217 return newMarshalErrorBefore(out, reflect.TypeOf(in), errChangingWhitespace) 218 } 219 } 220 } 221 err = marshalEncode(out, in, &xe.Struct) 222 if err != nil && xe.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { 223 return internal.TransformMarshalError(in, err) 224 } 225 return err 226 } 227 228 func marshalEncode(out *jsontext.Encoder, in any, mo *jsonopts.Struct) (err error) { 229 v := reflect.ValueOf(in) 230 if !v.IsValid() || (v.Kind() == reflect.Pointer && v.IsNil()) { 231 return out.WriteToken(jsontext.Null) 232 } 233 // Shallow copy non-pointer values to obtain an addressable value. 234 // It is beneficial to performance to always pass pointers to avoid this. 235 forceAddr := v.Kind() != reflect.Pointer 236 if forceAddr { 237 v2 := reflect.New(v.Type()) 238 v2.Elem().Set(v) 239 v = v2 240 } 241 va := addressableValue{v.Elem(), forceAddr} // dereferenced pointer is always addressable 242 t := va.Type() 243 244 // Lookup and call the marshal function for this type. 245 marshal := lookupArshaler(t).marshal 246 if mo.Marshalers != nil { 247 marshal, _ = mo.Marshalers.(*Marshalers).lookup(marshal, t) 248 } 249 if err := marshal(out, va, mo); err != nil { 250 if !mo.Flags.Get(jsonflags.AllowDuplicateNames) { 251 export.Encoder(out).Tokens.InvalidateDisabledNamespaces() 252 } 253 return err 254 } 255 return nil 256 } 257 258 // Unmarshal decodes a []byte input into a Go value according to the provided 259 // unmarshal and decode options (while ignoring marshal or encode options). 260 // The input must be a single JSON value with optional whitespace interspersed. 261 // The output must be a non-nil pointer. 262 // 263 // Type-specific unmarshal functions and methods take precedence 264 // over the default representation of a value. 265 // Functions or methods that operate on *T are only called when decoding 266 // a value of type T (by taking its address) or a non-nil value of *T. 267 // Unmarshal ensures that a value is always addressable 268 // (by copying the value if necessary) so that 269 // these functions and methods can be consistently called. 270 // If a value must be shallow copied to call a pointer-receiver 271 // [Unmarshaler], [UnmarshalerFrom], or [encoding.TextUnmarshaler] method, 272 // then any mutations performed by the method are shallow copied back 273 // into the destination value. 274 // 275 // The input is decoded into the output according to the following rules: 276 // 277 // - If any type-specific functions in a [WithUnmarshalers] option match 278 // the value type, then those functions are called to decode the JSON 279 // value. If all applicable functions return [errors.ErrUnsupported], 280 // then the input is decoded according to subsequent rules. 281 // 282 // - If the value type implements [UnmarshalerFrom], 283 // then the UnmarshalJSONFrom method is called to decode the JSON value. 284 // If the method returns [errors.ErrUnsupported], 285 // then the input is decoded according to subsequent rules. 286 // 287 // - If the value type implements [Unmarshaler], 288 // then the UnmarshalJSON method is called to decode the JSON value. 289 // 290 // - If the value type implements [encoding.TextUnmarshaler], 291 // then the input is decoded as a JSON string and 292 // the UnmarshalText method is called with the decoded string value. 293 // This fails with a [SemanticError] if the input is not a JSON string. 294 // 295 // - Otherwise, the JSON value is decoded according to the value's type 296 // as described in detail below. 297 // 298 // Most Go types have a default JSON representation. 299 // A JSON null may be decoded into every supported Go value where 300 // it is equivalent to storing the zero value of the Go value. 301 // If the input JSON kind is not handled by the current Go value type, 302 // then this fails with a [SemanticError]. Unless otherwise specified, 303 // the decoded value replaces any pre-existing value. 304 // 305 // The representation of each type is as follows: 306 // 307 // - A Go boolean is decoded from a JSON boolean (e.g., true or false). 308 // 309 // - A Go string is decoded from a JSON string. 310 // 311 // - A Go []byte or [N]byte is decoded from a JSON string containing 312 // a binary value using Base 64 Encoding per RFC 4648, section 4. 313 // When decoding into a non-nil []byte, the slice length is reset to zero 314 // and the decoded input is appended to it. 315 // When decoding into a [N]byte, the input must decode to exactly N bytes, 316 // otherwise it fails with a [SemanticError]. 317 // 318 // - A Go integer is decoded from a JSON number. 319 // It must be decoded from a JSON string containing a JSON number 320 // if [StringifyNumbers] is specified or decoding a JSON object name. 321 // It fails with a [SemanticError] if the JSON number 322 // has a fractional or exponent component. 323 // It also fails if it overflows the representation of the Go integer type. 324 // 325 // - A Go float is decoded from a JSON number. 326 // It must be decoded from a JSON string containing a JSON number 327 // if [StringifyNumbers] is specified or decoding a JSON object name. 328 // It fails if it overflows the representation of the Go float type. 329 // Since JSON lacks a native representation for a NaN or ±Inf, 330 // such values cannot be the result of decoding. 331 // 332 // - A Go map is decoded from a JSON object, 333 // where each JSON object name and value pair is recursively decoded 334 // as the Go map key and value. Maps are not cleared. 335 // If the Go map is nil, then a new map is allocated to decode into. 336 // If the decoded key matches an existing Go map entry, the entry value 337 // is reused by decoding the JSON object value into it. 338 // 339 // - A Go struct is decoded from a JSON object. 340 // See the “JSON Representation of Go structs” section 341 // in the package-level documentation for more details. 342 // 343 // - A Go slice is decoded from a JSON array, where each JSON element 344 // is recursively decoded and appended to the Go slice. 345 // Before appending into a Go slice, a new slice is allocated if it is nil, 346 // otherwise the slice length is reset to zero. 347 // 348 // - A Go array is decoded from a JSON array, where each JSON array element 349 // is recursively decoded as each corresponding Go array element. 350 // Each Go array element is zeroed before decoding into it. 351 // It fails with a [SemanticError] if the JSON array does not contain 352 // the exact same number of elements as the Go array. 353 // 354 // - A Go pointer is decoded based on the JSON kind and underlying Go type. 355 // If the input is a JSON null, then this stores a nil pointer. 356 // Otherwise, it allocates a new underlying value if the pointer is nil, 357 // and recursively JSON decodes into the underlying value. 358 // 359 // - A Go interface is decoded based on the JSON kind and underlying Go type. 360 // If the input is a JSON null, then this stores a nil interface value. 361 // Otherwise, a nil interface value of an empty interface type is initialized 362 // with a zero Go bool, string, float64, map[string]any, or []any if the 363 // input is a JSON boolean, string, number, object, or array, respectively. 364 // If the interface value is still nil, then this fails with a [SemanticError] 365 // since decoding could not determine an appropriate Go type to decode into. 366 // For example, unmarshaling into a nil io.Reader fails since 367 // there is no concrete type to populate the interface value with. 368 // Otherwise an underlying value exists and it recursively decodes 369 // the JSON input into it. 370 // 371 // - A Go [time.Time] is decoded from a JSON string containing the time 372 // formatted in RFC 3339 with nanosecond precision. 373 // 374 // - A Go [time.Duration] currently has no default representation and 375 // results in a [SemanticError], unless the [encoding/json.FormatDurationAsNano] 376 // option is specified, in which case it is decoded as a JSON number 377 // without fractions or exponents, representing the duration in nanoseconds. 378 // 379 // - All other Go types (e.g., complex numbers, channels, and functions) 380 // have no default representation and result in a [SemanticError]. 381 // 382 // In general, unmarshaling follows merge semantics (similar to RFC 7396) 383 // where the decoded Go value replaces the destination value 384 // for any JSON kind other than an object. 385 // For JSON objects, the input object is merged into the destination value 386 // where matching object members recursively apply merge semantics. 387 func Unmarshal(in []byte, out any, opts ...Options) (err error) { 388 dec := export.GetBufferedDecoder(in, opts...) 389 defer export.PutBufferedDecoder(dec) 390 xd := export.Decoder(dec) 391 err = unmarshalDecode(dec, out, &xd.Struct, true) 392 if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { 393 return internal.TransformUnmarshalError(out, err) 394 } 395 return err 396 } 397 398 // UnmarshalRead deserializes a Go value from an [io.Reader] according to the 399 // provided unmarshal and decode options (while ignoring marshal or encode options). 400 // The input must be a single JSON value with optional whitespace interspersed. 401 // It consumes the entirety of [io.Reader] until [io.EOF] is encountered, 402 // without reporting an error for EOF. The output must be a non-nil pointer. 403 // See [Unmarshal] for details about the conversion of JSON into a Go value. 404 func UnmarshalRead(in io.Reader, out any, opts ...Options) (err error) { 405 dec := export.GetStreamingDecoder(in, opts...) 406 defer export.PutStreamingDecoder(dec) 407 xd := export.Decoder(dec) 408 err = unmarshalDecode(dec, out, &xd.Struct, true) 409 if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { 410 return internal.TransformUnmarshalError(out, err) 411 } 412 return err 413 } 414 415 // UnmarshalDecode deserializes a Go value from a [jsontext.Decoder] according to 416 // the provided unmarshal or decode options (while ignoring marshal or encode options). 417 // The options provided take precedence over options already applied on 418 // the [jsontext.Decoder] and only apply for the duration of the unmarshal call. 419 // 420 // The input may be a stream of zero or more JSON values, 421 // where this only unmarshals the next JSON value in the stream. 422 // If there are no more top-level JSON values, it reports [io.EOF]. 423 // The output must be a non-nil pointer. 424 // See [Unmarshal] for details about the conversion of JSON into a Go value. 425 func UnmarshalDecode(in *jsontext.Decoder, out any, opts ...Options) (err error) { 426 xd := export.Decoder(in) 427 if len(opts) > 0 { 428 optsOriginal := xd.Struct 429 defer func() { xd.Struct = optsOriginal }() 430 xd.Struct.Join(opts...) 431 if xd.Tokens.Last.NeedObjectName() { 432 if optsOriginal.Flags.Get(jsonflags.AllowDuplicateNames) != xd.Struct.Flags.Get(jsonflags.AllowDuplicateNames) { 433 return newUnmarshalErrorBefore(in, reflect.TypeOf(out), errChangingDuplicateNames) 434 } 435 if optsOriginal.Flags.Get(jsonflags.AllowInvalidUTF8) != xd.Struct.Flags.Get(jsonflags.AllowInvalidUTF8) { 436 return newUnmarshalErrorBefore(in, reflect.TypeOf(out), errChangingInvalidUTF8) 437 } 438 } 439 } 440 err = unmarshalDecode(in, out, &xd.Struct, false) 441 if err != nil && xd.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { 442 return internal.TransformUnmarshalError(out, err) 443 } 444 return err 445 } 446 447 func unmarshalDecode(in *jsontext.Decoder, out any, uo *jsonopts.Struct, last bool) (err error) { 448 v := reflect.ValueOf(out) 449 if v.Kind() != reflect.Pointer || v.IsNil() { 450 return &SemanticError{action: "unmarshal", GoType: reflect.TypeOf(out), Err: internal.ErrNonNilReference} 451 } 452 va := addressableValue{v.Elem(), false} // dereferenced pointer is always addressable 453 t := va.Type() 454 455 // In legacy semantics, the entirety of the next JSON value 456 // was validated before attempting to unmarshal it. 457 if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { 458 if err := export.Decoder(in).CheckNextValue(last); err != nil { 459 if err == io.EOF && last { 460 offset := in.InputOffset() + int64(len(in.UnreadBuffer())) 461 return &jsontext.SyntacticError{ByteOffset: offset, Err: io.ErrUnexpectedEOF} 462 } 463 return err 464 } 465 } 466 467 // Lookup and call the unmarshal function for this type. 468 unmarshal := lookupArshaler(t).unmarshal 469 if uo.Unmarshalers != nil { 470 unmarshal, _ = uo.Unmarshalers.(*Unmarshalers).lookup(unmarshal, t) 471 } 472 if err := unmarshal(in, va, uo); err != nil { 473 if !uo.Flags.Get(jsonflags.AllowDuplicateNames) { 474 export.Decoder(in).Tokens.InvalidateDisabledNamespaces() 475 } 476 if err == io.EOF && last { 477 offset := in.InputOffset() + int64(len(in.UnreadBuffer())) 478 return &jsontext.SyntacticError{ByteOffset: offset, Err: io.ErrUnexpectedEOF} 479 } 480 return err 481 } 482 if last { 483 return export.Decoder(in).CheckEOF() 484 } 485 return nil 486 } 487 488 // addressableValue is a reflect.Value that is guaranteed to be addressable 489 // such that calling the Addr and Set methods do not panic. 490 // 491 // There is no compile magic that enforces this property, 492 // but rather the need to construct this type makes it easier to examine each 493 // construction site to ensure that this property is upheld. 494 type addressableValue struct { 495 reflect.Value 496 497 // forcedAddr reports whether this value is addressable 498 // only through the use of [newAddressableValue]. 499 // This is only used for [jsonflags.CallMethodsWithLegacySemantics]. 500 forcedAddr bool 501 } 502 503 // newAddressableValue constructs a new addressable value of type t. 504 func newAddressableValue(t reflect.Type) addressableValue { 505 return addressableValue{reflect.New(t).Elem(), true} 506 } 507 508 // TODO: Remove *jsonopts.Struct argument from [marshaler] and [unmarshaler]. 509 // This can be directly accessed on the encoder or decoder. 510 511 // All marshal and unmarshal behavior is implemented using these signatures. 512 // The *jsonopts.Struct argument is guaranteed to be identical to or at least 513 // a strict super-set of the options in Encoder.Struct or Decoder.Struct. 514 // It is identical for Marshal, Unmarshal, MarshalWrite, and UnmarshalRead. 515 // It is a super-set for MarshalEncode and UnmarshalDecode. 516 type ( 517 marshaler = func(*jsontext.Encoder, addressableValue, *jsonopts.Struct) error 518 unmarshaler = func(*jsontext.Decoder, addressableValue, *jsonopts.Struct) error 519 ) 520 521 type arshaler struct { 522 marshal marshaler 523 unmarshal unmarshaler 524 nonDefault bool 525 } 526 527 var lookupArshalerCache sync.Map // map[reflect.Type]*arshaler 528 529 func lookupArshaler(t reflect.Type) *arshaler { 530 if v, ok := lookupArshalerCache.Load(t); ok { 531 return v.(*arshaler) 532 } 533 534 fncs := makeDefaultArshaler(t) 535 fncs = makeMethodArshaler(fncs, t) 536 fncs = makeTimeArshaler(fncs, t) 537 538 // Use the last stored so that duplicate arshalers can be garbage collected. 539 v, _ := lookupArshalerCache.LoadOrStore(t, fncs) 540 return v.(*arshaler) 541 } 542 543 var stringsPools = &sync.Pool{New: func() any { return new(stringSlice) }} 544 545 type stringSlice []string 546 547 // getStrings returns a non-nil pointer to a slice with length n. 548 func getStrings(n int) *stringSlice { 549 s := stringsPools.Get().(*stringSlice) 550 if cap(*s) < n { 551 *s = make([]string, n) 552 } 553 *s = (*s)[:n] 554 return s 555 } 556 557 func putStrings(s *stringSlice) { 558 if cap(*s) > 1<<10 { 559 *s = nil // avoid pinning arbitrarily large amounts of memory 560 } 561 clear(*s) // avoid pinning a reference to each string 562 stringsPools.Put(s) 563 } 564