mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 02:33:34 +00:00
rebase: bump k8s.io/api
Bumps the k8s-dependencies group with 1 update in the /api directory: [k8s.io/api](https://github.com/kubernetes/api). Updates `k8s.io/api` from 0.31.3 to 0.32.1 - [Commits](https://github.com/kubernetes/api/compare/v0.31.3...v0.32.1) --- updated-dependencies: - dependency-name: k8s.io/api dependency-type: direct:production update-type: version-update:semver-minor dependency-group: k8s-dependencies ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
committed by
mergify[bot]
parent
8a66575825
commit
5aef21ea4e
2
vendor/sigs.k8s.io/json/Makefile
generated
vendored
2
vendor/sigs.k8s.io/json/Makefile
generated
vendored
@ -19,7 +19,7 @@ vet:
|
||||
go vet sigs.k8s.io/json
|
||||
|
||||
@echo "checking for external dependencies"
|
||||
@deps=$$(go mod graph); \
|
||||
@deps=$$(go list -f '{{ if not (or .Standard .Module.Main) }}{{.ImportPath}}{{ end }}' -deps sigs.k8s.io/json/... || true); \
|
||||
if [ -n "$${deps}" ]; then \
|
||||
echo "only stdlib dependencies allowed, found:"; \
|
||||
echo "$${deps}"; \
|
||||
|
2
vendor/sigs.k8s.io/json/OWNERS
generated
vendored
2
vendor/sigs.k8s.io/json/OWNERS
generated
vendored
@ -2,5 +2,5 @@
|
||||
|
||||
approvers:
|
||||
- deads2k
|
||||
- lavalamp
|
||||
- jpbetz
|
||||
- liggitt
|
||||
|
140
vendor/sigs.k8s.io/json/internal/golang/encoding/json/decode.go
generated
vendored
140
vendor/sigs.k8s.io/json/internal/golang/encoding/json/decode.go
generated
vendored
@ -21,10 +21,10 @@ import (
|
||||
|
||||
// Unmarshal parses the JSON-encoded data and stores the result
|
||||
// in the value pointed to by v. If v is nil or not a pointer,
|
||||
// Unmarshal returns an InvalidUnmarshalError.
|
||||
// Unmarshal returns an [InvalidUnmarshalError].
|
||||
//
|
||||
// Unmarshal uses the inverse of the encodings that
|
||||
// Marshal uses, allocating maps, slices, and pointers as necessary,
|
||||
// [Marshal] uses, allocating maps, slices, and pointers as necessary,
|
||||
// with the following additional rules:
|
||||
//
|
||||
// To unmarshal JSON into a pointer, Unmarshal first handles the case of
|
||||
@ -33,28 +33,28 @@ import (
|
||||
// the value pointed at by the pointer. If the pointer is nil, Unmarshal
|
||||
// allocates a new value for it to point to.
|
||||
//
|
||||
// To unmarshal JSON into a value implementing the Unmarshaler interface,
|
||||
// Unmarshal calls that value's UnmarshalJSON method, including
|
||||
// To unmarshal JSON into a value implementing [Unmarshaler],
|
||||
// Unmarshal calls that value's [Unmarshaler.UnmarshalJSON] method, including
|
||||
// when the input is a JSON null.
|
||||
// Otherwise, if the value implements encoding.TextUnmarshaler
|
||||
// and the input is a JSON quoted string, Unmarshal calls that value's
|
||||
// UnmarshalText method with the unquoted form of the string.
|
||||
// Otherwise, if the value implements [encoding.TextUnmarshaler]
|
||||
// and the input is a JSON quoted string, Unmarshal calls
|
||||
// [encoding.TextUnmarshaler.UnmarshalText] with the unquoted form of the string.
|
||||
//
|
||||
// To unmarshal JSON into a struct, Unmarshal matches incoming object
|
||||
// keys to the keys used by Marshal (either the struct field name or its tag),
|
||||
// keys to the keys used by [Marshal] (either the struct field name or its tag),
|
||||
// preferring an exact match but also accepting a case-insensitive match. By
|
||||
// default, object keys which don't have a corresponding struct field are
|
||||
// ignored (see Decoder.DisallowUnknownFields for an alternative).
|
||||
// ignored (see [Decoder.DisallowUnknownFields] for an alternative).
|
||||
//
|
||||
// To unmarshal JSON into an interface value,
|
||||
// Unmarshal stores one of these in the interface value:
|
||||
//
|
||||
// bool, for JSON booleans
|
||||
// float64, for JSON numbers
|
||||
// string, for JSON strings
|
||||
// []interface{}, for JSON arrays
|
||||
// map[string]interface{}, for JSON objects
|
||||
// nil for JSON null
|
||||
// - bool, for JSON booleans
|
||||
// - float64, for JSON numbers
|
||||
// - string, for JSON strings
|
||||
// - []interface{}, for JSON arrays
|
||||
// - map[string]interface{}, for JSON objects
|
||||
// - nil for JSON null
|
||||
//
|
||||
// To unmarshal a JSON array into a slice, Unmarshal resets the slice length
|
||||
// to zero and then appends each element to the slice.
|
||||
@ -72,16 +72,15 @@ import (
|
||||
// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal
|
||||
// reuses the existing map, keeping existing entries. Unmarshal then stores
|
||||
// key-value pairs from the JSON object into the map. The map's key type must
|
||||
// either be any string type, an integer, implement json.Unmarshaler, or
|
||||
// implement encoding.TextUnmarshaler.
|
||||
// either be any string type, an integer, or implement [encoding.TextUnmarshaler].
|
||||
//
|
||||
// If the JSON-encoded data contain a syntax error, Unmarshal returns a SyntaxError.
|
||||
// If the JSON-encoded data contain a syntax error, Unmarshal returns a [SyntaxError].
|
||||
//
|
||||
// If a JSON value is not appropriate for a given target type,
|
||||
// or if a JSON number overflows the target type, Unmarshal
|
||||
// skips that field and completes the unmarshaling as best it can.
|
||||
// If no more serious errors are encountered, Unmarshal returns
|
||||
// an UnmarshalTypeError describing the earliest such error. In any
|
||||
// an [UnmarshalTypeError] describing the earliest such error. In any
|
||||
// case, it's not guaranteed that all the remaining fields following
|
||||
// the problematic one will be unmarshaled into the target object.
|
||||
//
|
||||
@ -119,7 +118,7 @@ func Unmarshal(data []byte, v any, opts ...UnmarshalOpt) error {
|
||||
// a JSON value. UnmarshalJSON must copy the JSON data
|
||||
// if it wishes to retain the data after returning.
|
||||
//
|
||||
// By convention, to approximate the behavior of Unmarshal itself,
|
||||
// By convention, to approximate the behavior of [Unmarshal] itself,
|
||||
// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op.
|
||||
type Unmarshaler interface {
|
||||
UnmarshalJSON([]byte) error
|
||||
@ -157,8 +156,8 @@ func (e *UnmarshalFieldError) Error() string {
|
||||
return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String()
|
||||
}
|
||||
|
||||
// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
|
||||
// (The argument to Unmarshal must be a non-nil pointer.)
|
||||
// An InvalidUnmarshalError describes an invalid argument passed to [Unmarshal].
|
||||
// (The argument to [Unmarshal] must be a non-nil pointer.)
|
||||
type InvalidUnmarshalError struct {
|
||||
Type reflect.Type
|
||||
}
|
||||
@ -573,17 +572,10 @@ func (d *decodeState) array(v reflect.Value) error {
|
||||
break
|
||||
}
|
||||
|
||||
// Get element of array, growing if necessary.
|
||||
// Expand slice length, growing the slice if necessary.
|
||||
if v.Kind() == reflect.Slice {
|
||||
// Grow slice if necessary
|
||||
if i >= v.Cap() {
|
||||
newcap := v.Cap() + v.Cap()/2
|
||||
if newcap < 4 {
|
||||
newcap = 4
|
||||
}
|
||||
newv := reflect.MakeSlice(v.Type(), v.Len(), newcap)
|
||||
reflect.Copy(newv, v)
|
||||
v.Set(newv)
|
||||
v.Grow(1)
|
||||
}
|
||||
if i >= v.Len() {
|
||||
v.SetLen(i + 1)
|
||||
@ -620,13 +612,11 @@ func (d *decodeState) array(v reflect.Value) error {
|
||||
|
||||
if i < v.Len() {
|
||||
if v.Kind() == reflect.Array {
|
||||
// Array. Zero the rest.
|
||||
z := reflect.Zero(v.Type().Elem())
|
||||
for ; i < v.Len(); i++ {
|
||||
v.Index(i).Set(z)
|
||||
v.Index(i).SetZero() // zero remainder of array
|
||||
}
|
||||
} else {
|
||||
v.SetLen(i)
|
||||
v.SetLen(i) // truncate the slice
|
||||
}
|
||||
}
|
||||
if i == 0 && v.Kind() == reflect.Slice {
|
||||
@ -636,7 +626,7 @@ func (d *decodeState) array(v reflect.Value) error {
|
||||
}
|
||||
|
||||
var nullLiteral = []byte("null")
|
||||
var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
|
||||
var textUnmarshalerType = reflect.TypeFor[encoding.TextUnmarshaler]()
|
||||
|
||||
// object consumes an object from d.data[d.off-1:], decoding into v.
|
||||
// The first byte ('{') of the object has been read already.
|
||||
@ -776,7 +766,7 @@ func (d *decodeState) object(v reflect.Value) error {
|
||||
if !mapElem.IsValid() {
|
||||
mapElem = reflect.New(elemType).Elem()
|
||||
} else {
|
||||
mapElem.Set(reflect.Zero(elemType))
|
||||
mapElem.SetZero()
|
||||
}
|
||||
subv = mapElem
|
||||
if checkDuplicateField != nil {
|
||||
@ -784,28 +774,14 @@ func (d *decodeState) object(v reflect.Value) error {
|
||||
}
|
||||
d.appendStrictFieldStackKey(string(key))
|
||||
} else {
|
||||
var f *field
|
||||
if i, ok := fields.nameIndex[string(key)]; ok {
|
||||
// Found an exact name match.
|
||||
f = &fields.list[i]
|
||||
if checkDuplicateField != nil {
|
||||
checkDuplicateField(i, f.name)
|
||||
}
|
||||
} else if !d.caseSensitive {
|
||||
// Fall back to the expensive case-insensitive
|
||||
// linear search.
|
||||
for i := range fields.list {
|
||||
ff := &fields.list[i]
|
||||
if ff.equalFold(ff.nameBytes, key) {
|
||||
f = ff
|
||||
if checkDuplicateField != nil {
|
||||
checkDuplicateField(i, f.name)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
f := fields.byExactName[string(key)]
|
||||
if f == nil && !d.caseSensitive {
|
||||
f = fields.byFoldedName[string(foldName(key))]
|
||||
}
|
||||
if f != nil {
|
||||
if checkDuplicateField != nil {
|
||||
checkDuplicateField(f.listIndex, f.name)
|
||||
}
|
||||
subv = v
|
||||
destring = f.quoted
|
||||
for _, i := range f.index {
|
||||
@ -874,33 +850,35 @@ func (d *decodeState) object(v reflect.Value) error {
|
||||
if v.Kind() == reflect.Map {
|
||||
kt := t.Key()
|
||||
var kv reflect.Value
|
||||
switch {
|
||||
case reflect.PointerTo(kt).Implements(textUnmarshalerType):
|
||||
if reflect.PointerTo(kt).Implements(textUnmarshalerType) {
|
||||
kv = reflect.New(kt)
|
||||
if err := d.literalStore(item, kv, true); err != nil {
|
||||
return err
|
||||
}
|
||||
kv = kv.Elem()
|
||||
case kt.Kind() == reflect.String:
|
||||
kv = reflect.ValueOf(key).Convert(kt)
|
||||
default:
|
||||
} else {
|
||||
switch kt.Kind() {
|
||||
case reflect.String:
|
||||
kv = reflect.New(kt).Elem()
|
||||
kv.SetString(string(key))
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
s := string(key)
|
||||
n, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil || reflect.Zero(kt).OverflowInt(n) {
|
||||
if err != nil || kt.OverflowInt(n) {
|
||||
d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)})
|
||||
break
|
||||
}
|
||||
kv = reflect.ValueOf(n).Convert(kt)
|
||||
kv = reflect.New(kt).Elem()
|
||||
kv.SetInt(n)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
s := string(key)
|
||||
n, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil || reflect.Zero(kt).OverflowUint(n) {
|
||||
if err != nil || kt.OverflowUint(n) {
|
||||
d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)})
|
||||
break
|
||||
}
|
||||
kv = reflect.ValueOf(n).Convert(kt)
|
||||
kv = reflect.New(kt).Elem()
|
||||
kv.SetUint(n)
|
||||
default:
|
||||
panic("json: Unexpected key type") // should never occur
|
||||
}
|
||||
@ -950,12 +928,12 @@ func (d *decodeState) convertNumber(s string) (any, error) {
|
||||
|
||||
f, err := strconv.ParseFloat(s, 64)
|
||||
if err != nil {
|
||||
return nil, &UnmarshalTypeError{Value: "number " + s, Type: reflect.TypeOf(0.0), Offset: int64(d.off)}
|
||||
return nil, &UnmarshalTypeError{Value: "number " + s, Type: reflect.TypeFor[float64](), Offset: int64(d.off)}
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
var numberType = reflect.TypeOf(Number(""))
|
||||
var numberType = reflect.TypeFor[Number]()
|
||||
|
||||
// literalStore decodes a literal stored in item into v.
|
||||
//
|
||||
@ -965,7 +943,7 @@ var numberType = reflect.TypeOf(Number(""))
|
||||
func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) error {
|
||||
// Check for unmarshaler.
|
||||
if len(item) == 0 {
|
||||
//Empty string given
|
||||
// Empty string given.
|
||||
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
|
||||
return nil
|
||||
}
|
||||
@ -1012,7 +990,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||
}
|
||||
switch v.Kind() {
|
||||
case reflect.Interface, reflect.Pointer, reflect.Map, reflect.Slice:
|
||||
v.Set(reflect.Zero(v.Type()))
|
||||
v.SetZero()
|
||||
// otherwise, ignore null for primitives/string
|
||||
}
|
||||
case 't', 'f': // true, false
|
||||
@ -1064,10 +1042,11 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||
}
|
||||
v.SetBytes(b[:n])
|
||||
case reflect.String:
|
||||
if v.Type() == numberType && !isValidNumber(string(s)) {
|
||||
t := string(s)
|
||||
if v.Type() == numberType && !isValidNumber(t) {
|
||||
return fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item)
|
||||
}
|
||||
v.SetString(string(s))
|
||||
v.SetString(t)
|
||||
case reflect.Interface:
|
||||
if v.NumMethod() == 0 {
|
||||
v.Set(reflect.ValueOf(string(s)))
|
||||
@ -1083,13 +1062,12 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||
}
|
||||
panic(phasePanicMsg)
|
||||
}
|
||||
s := string(item)
|
||||
switch v.Kind() {
|
||||
default:
|
||||
if v.Kind() == reflect.String && v.Type() == numberType {
|
||||
// s must be a valid number, because it's
|
||||
// already been tokenized.
|
||||
v.SetString(s)
|
||||
v.SetString(string(item))
|
||||
break
|
||||
}
|
||||
if fromQuoted {
|
||||
@ -1097,7 +1075,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||
}
|
||||
d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())})
|
||||
case reflect.Interface:
|
||||
n, err := d.convertNumber(s)
|
||||
n, err := d.convertNumber(string(item))
|
||||
if err != nil {
|
||||
d.saveError(err)
|
||||
break
|
||||
@ -1109,25 +1087,25 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
||||
v.Set(reflect.ValueOf(n))
|
||||
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
n, err := strconv.ParseInt(s, 10, 64)
|
||||
n, err := strconv.ParseInt(string(item), 10, 64)
|
||||
if err != nil || v.OverflowInt(n) {
|
||||
d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())})
|
||||
d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())})
|
||||
break
|
||||
}
|
||||
v.SetInt(n)
|
||||
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
n, err := strconv.ParseUint(s, 10, 64)
|
||||
n, err := strconv.ParseUint(string(item), 10, 64)
|
||||
if err != nil || v.OverflowUint(n) {
|
||||
d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())})
|
||||
d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())})
|
||||
break
|
||||
}
|
||||
v.SetUint(n)
|
||||
|
||||
case reflect.Float32, reflect.Float64:
|
||||
n, err := strconv.ParseFloat(s, v.Type().Bits())
|
||||
n, err := strconv.ParseFloat(string(item), v.Type().Bits())
|
||||
if err != nil || v.OverflowFloat(n) {
|
||||
d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())})
|
||||
d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())})
|
||||
break
|
||||
}
|
||||
v.SetFloat(n)
|
||||
|
492
vendor/sigs.k8s.io/json/internal/golang/encoding/json/encode.go
generated
vendored
492
vendor/sigs.k8s.io/json/internal/golang/encoding/json/encode.go
generated
vendored
@ -12,12 +12,13 @@ package json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmp"
|
||||
"encoding"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"sort"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -28,29 +29,30 @@ import (
|
||||
// Marshal returns the JSON encoding of v.
|
||||
//
|
||||
// Marshal traverses the value v recursively.
|
||||
// If an encountered value implements the Marshaler interface
|
||||
// and is not a nil pointer, Marshal calls its MarshalJSON method
|
||||
// to produce JSON. If no MarshalJSON method is present but the
|
||||
// value implements encoding.TextMarshaler instead, Marshal calls
|
||||
// its MarshalText method and encodes the result as a JSON string.
|
||||
// If an encountered value implements [Marshaler]
|
||||
// and is not a nil pointer, Marshal calls [Marshaler.MarshalJSON]
|
||||
// to produce JSON. If no [Marshaler.MarshalJSON] method is present but the
|
||||
// value implements [encoding.TextMarshaler] instead, Marshal calls
|
||||
// [encoding.TextMarshaler.MarshalText] and encodes the result as a JSON string.
|
||||
// The nil pointer exception is not strictly necessary
|
||||
// but mimics a similar, necessary exception in the behavior of
|
||||
// UnmarshalJSON.
|
||||
// [Unmarshaler.UnmarshalJSON].
|
||||
//
|
||||
// Otherwise, Marshal uses the following type-dependent default encodings:
|
||||
//
|
||||
// Boolean values encode as JSON booleans.
|
||||
//
|
||||
// Floating point, integer, and Number values encode as JSON numbers.
|
||||
// Floating point, integer, and [Number] values encode as JSON numbers.
|
||||
// NaN and +/-Inf values will return an [UnsupportedValueError].
|
||||
//
|
||||
// String values encode as JSON strings coerced to valid UTF-8,
|
||||
// replacing invalid bytes with the Unicode replacement rune.
|
||||
// So that the JSON will be safe to embed inside HTML <script> tags,
|
||||
// the string is encoded using HTMLEscape,
|
||||
// the string is encoded using [HTMLEscape],
|
||||
// which replaces "<", ">", "&", U+2028, and U+2029 are escaped
|
||||
// to "\u003c","\u003e", "\u0026", "\u2028", and "\u2029".
|
||||
// This replacement can be disabled when using an Encoder,
|
||||
// by calling SetEscapeHTML(false).
|
||||
// This replacement can be disabled when using an [Encoder],
|
||||
// by calling [Encoder.SetEscapeHTML](false).
|
||||
//
|
||||
// Array and slice values encode as JSON arrays, except that
|
||||
// []byte encodes as a base64-encoded string, and a nil slice
|
||||
@ -107,7 +109,7 @@ import (
|
||||
// only Unicode letters, digits, and ASCII punctuation except quotation
|
||||
// marks, backslash, and comma.
|
||||
//
|
||||
// Anonymous struct fields are usually marshaled as if their inner exported fields
|
||||
// Embedded struct fields are usually marshaled as if their inner exported fields
|
||||
// were fields in the outer struct, subject to the usual Go visibility rules amended
|
||||
// as described in the next paragraph.
|
||||
// An anonymous struct field with a name given in its JSON tag is treated as
|
||||
@ -134,11 +136,11 @@ import (
|
||||
// a JSON tag of "-".
|
||||
//
|
||||
// Map values encode as JSON objects. The map's key type must either be a
|
||||
// string, an integer type, or implement encoding.TextMarshaler. The map keys
|
||||
// string, an integer type, or implement [encoding.TextMarshaler]. The map keys
|
||||
// are sorted and used as JSON object keys by applying the following rules,
|
||||
// subject to the UTF-8 coercion described for string values above:
|
||||
// - keys of any string type are used directly
|
||||
// - encoding.TextMarshalers are marshaled
|
||||
// - keys that implement [encoding.TextMarshaler] are marshaled
|
||||
// - integer keys are converted to strings
|
||||
//
|
||||
// Pointer values encode as the value pointed to.
|
||||
@ -149,13 +151,14 @@ import (
|
||||
//
|
||||
// Channel, complex, and function values cannot be encoded in JSON.
|
||||
// Attempting to encode such a value causes Marshal to return
|
||||
// an UnsupportedTypeError.
|
||||
// an [UnsupportedTypeError].
|
||||
//
|
||||
// JSON cannot represent cyclic data structures and Marshal does not
|
||||
// handle them. Passing cyclic structures to Marshal will result in
|
||||
// an error.
|
||||
func Marshal(v any) ([]byte, error) {
|
||||
e := newEncodeState()
|
||||
defer encodeStatePool.Put(e)
|
||||
|
||||
err := e.marshal(v, encOpts{escapeHTML: true})
|
||||
if err != nil {
|
||||
@ -163,12 +166,10 @@ func Marshal(v any) ([]byte, error) {
|
||||
}
|
||||
buf := append([]byte(nil), e.Bytes()...)
|
||||
|
||||
encodeStatePool.Put(e)
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// MarshalIndent is like Marshal but applies Indent to format the output.
|
||||
// MarshalIndent is like [Marshal] but applies [Indent] to format the output.
|
||||
// Each JSON element in the output will begin on a new line beginning with prefix
|
||||
// followed by one or more copies of indent according to the indentation nesting.
|
||||
func MarshalIndent(v any, prefix, indent string) ([]byte, error) {
|
||||
@ -176,47 +177,12 @@ func MarshalIndent(v any, prefix, indent string) ([]byte, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
err = Indent(&buf, b, prefix, indent)
|
||||
b2 := make([]byte, 0, indentGrowthFactor*len(b))
|
||||
b2, err = appendIndent(b2, b, prefix, indent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029
|
||||
// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029
|
||||
// so that the JSON will be safe to embed inside HTML <script> tags.
|
||||
// For historical reasons, web browsers don't honor standard HTML
|
||||
// escaping within <script> tags, so an alternative JSON encoding must
|
||||
// be used.
|
||||
func HTMLEscape(dst *bytes.Buffer, src []byte) {
|
||||
// The characters can only appear in string literals,
|
||||
// so just scan the string one byte at a time.
|
||||
start := 0
|
||||
for i, c := range src {
|
||||
if c == '<' || c == '>' || c == '&' {
|
||||
if start < i {
|
||||
dst.Write(src[start:i])
|
||||
}
|
||||
dst.WriteString(`\u00`)
|
||||
dst.WriteByte(hex[c>>4])
|
||||
dst.WriteByte(hex[c&0xF])
|
||||
start = i + 1
|
||||
}
|
||||
// Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9).
|
||||
if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 {
|
||||
if start < i {
|
||||
dst.Write(src[start:i])
|
||||
}
|
||||
dst.WriteString(`\u202`)
|
||||
dst.WriteByte(hex[src[i+2]&0xF])
|
||||
start = i + 3
|
||||
}
|
||||
}
|
||||
if start < len(src) {
|
||||
dst.Write(src[start:])
|
||||
}
|
||||
return b2, nil
|
||||
}
|
||||
|
||||
// Marshaler is the interface implemented by types that
|
||||
@ -225,7 +191,7 @@ type Marshaler interface {
|
||||
MarshalJSON() ([]byte, error)
|
||||
}
|
||||
|
||||
// An UnsupportedTypeError is returned by Marshal when attempting
|
||||
// An UnsupportedTypeError is returned by [Marshal] when attempting
|
||||
// to encode an unsupported value type.
|
||||
type UnsupportedTypeError struct {
|
||||
Type reflect.Type
|
||||
@ -235,7 +201,7 @@ func (e *UnsupportedTypeError) Error() string {
|
||||
return "json: unsupported type: " + e.Type.String()
|
||||
}
|
||||
|
||||
// An UnsupportedValueError is returned by Marshal when attempting
|
||||
// An UnsupportedValueError is returned by [Marshal] when attempting
|
||||
// to encode an unsupported value.
|
||||
type UnsupportedValueError struct {
|
||||
Value reflect.Value
|
||||
@ -246,9 +212,9 @@ func (e *UnsupportedValueError) Error() string {
|
||||
return "json: unsupported value: " + e.Str
|
||||
}
|
||||
|
||||
// Before Go 1.2, an InvalidUTF8Error was returned by Marshal when
|
||||
// Before Go 1.2, an InvalidUTF8Error was returned by [Marshal] when
|
||||
// attempting to encode a string value with invalid UTF-8 sequences.
|
||||
// As of Go 1.2, Marshal instead coerces the string to valid UTF-8 by
|
||||
// As of Go 1.2, [Marshal] instead coerces the string to valid UTF-8 by
|
||||
// replacing invalid bytes with the Unicode replacement rune U+FFFD.
|
||||
//
|
||||
// Deprecated: No longer used; kept for compatibility.
|
||||
@ -260,7 +226,8 @@ func (e *InvalidUTF8Error) Error() string {
|
||||
return "json: invalid UTF-8 in string: " + strconv.Quote(e.S)
|
||||
}
|
||||
|
||||
// A MarshalerError represents an error from calling a MarshalJSON or MarshalText method.
|
||||
// A MarshalerError represents an error from calling a
|
||||
// [Marshaler.MarshalJSON] or [encoding.TextMarshaler.MarshalText] method.
|
||||
type MarshalerError struct {
|
||||
Type reflect.Type
|
||||
Err error
|
||||
@ -280,12 +247,11 @@ func (e *MarshalerError) Error() string {
|
||||
// Unwrap returns the underlying error.
|
||||
func (e *MarshalerError) Unwrap() error { return e.Err }
|
||||
|
||||
var hex = "0123456789abcdef"
|
||||
const hex = "0123456789abcdef"
|
||||
|
||||
// An encodeState encodes JSON into a bytes.Buffer.
|
||||
type encodeState struct {
|
||||
bytes.Buffer // accumulated output
|
||||
scratch [64]byte
|
||||
|
||||
// Keep track of what pointers we've seen in the current recursive call
|
||||
// path, to avoid cycles that could lead to a stack overflow. Only do
|
||||
@ -341,16 +307,12 @@ func isEmptyValue(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||
return v.Len() == 0
|
||||
case reflect.Bool:
|
||||
return !v.Bool()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float() == 0
|
||||
case reflect.Interface, reflect.Pointer:
|
||||
return v.IsNil()
|
||||
case reflect.Bool,
|
||||
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
|
||||
reflect.Float32, reflect.Float64,
|
||||
reflect.Interface, reflect.Pointer:
|
||||
return v.IsZero()
|
||||
}
|
||||
return false
|
||||
}
|
||||
@ -407,8 +369,8 @@ func typeEncoder(t reflect.Type) encoderFunc {
|
||||
}
|
||||
|
||||
var (
|
||||
marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
|
||||
textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
|
||||
marshalerType = reflect.TypeFor[Marshaler]()
|
||||
textMarshalerType = reflect.TypeFor[encoding.TextMarshaler]()
|
||||
)
|
||||
|
||||
// newTypeEncoder constructs an encoderFunc for a type.
|
||||
@ -477,8 +439,10 @@ func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
}
|
||||
b, err := m.MarshalJSON()
|
||||
if err == nil {
|
||||
// copy JSON into buffer, checking validity.
|
||||
err = compact(&e.Buffer, b, opts.escapeHTML)
|
||||
e.Grow(len(b))
|
||||
out := e.AvailableBuffer()
|
||||
out, err = appendCompact(out, b, opts.escapeHTML)
|
||||
e.Buffer.Write(out)
|
||||
}
|
||||
if err != nil {
|
||||
e.error(&MarshalerError{v.Type(), err, "MarshalJSON"})
|
||||
@ -494,8 +458,10 @@ func addrMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
m := va.Interface().(Marshaler)
|
||||
b, err := m.MarshalJSON()
|
||||
if err == nil {
|
||||
// copy JSON into buffer, checking validity.
|
||||
err = compact(&e.Buffer, b, opts.escapeHTML)
|
||||
e.Grow(len(b))
|
||||
out := e.AvailableBuffer()
|
||||
out, err = appendCompact(out, b, opts.escapeHTML)
|
||||
e.Buffer.Write(out)
|
||||
}
|
||||
if err != nil {
|
||||
e.error(&MarshalerError{v.Type(), err, "MarshalJSON"})
|
||||
@ -516,7 +482,7 @@ func textMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
if err != nil {
|
||||
e.error(&MarshalerError{v.Type(), err, "MarshalText"})
|
||||
}
|
||||
e.stringBytes(b, opts.escapeHTML)
|
||||
e.Write(appendString(e.AvailableBuffer(), b, opts.escapeHTML))
|
||||
}
|
||||
|
||||
func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
@ -530,43 +496,31 @@ func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
if err != nil {
|
||||
e.error(&MarshalerError{v.Type(), err, "MarshalText"})
|
||||
}
|
||||
e.stringBytes(b, opts.escapeHTML)
|
||||
e.Write(appendString(e.AvailableBuffer(), b, opts.escapeHTML))
|
||||
}
|
||||
|
||||
func boolEncoder(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
if opts.quoted {
|
||||
e.WriteByte('"')
|
||||
}
|
||||
if v.Bool() {
|
||||
e.WriteString("true")
|
||||
} else {
|
||||
e.WriteString("false")
|
||||
}
|
||||
if opts.quoted {
|
||||
e.WriteByte('"')
|
||||
}
|
||||
b := e.AvailableBuffer()
|
||||
b = mayAppendQuote(b, opts.quoted)
|
||||
b = strconv.AppendBool(b, v.Bool())
|
||||
b = mayAppendQuote(b, opts.quoted)
|
||||
e.Write(b)
|
||||
}
|
||||
|
||||
func intEncoder(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
b := strconv.AppendInt(e.scratch[:0], v.Int(), 10)
|
||||
if opts.quoted {
|
||||
e.WriteByte('"')
|
||||
}
|
||||
b := e.AvailableBuffer()
|
||||
b = mayAppendQuote(b, opts.quoted)
|
||||
b = strconv.AppendInt(b, v.Int(), 10)
|
||||
b = mayAppendQuote(b, opts.quoted)
|
||||
e.Write(b)
|
||||
if opts.quoted {
|
||||
e.WriteByte('"')
|
||||
}
|
||||
}
|
||||
|
||||
func uintEncoder(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
b := strconv.AppendUint(e.scratch[:0], v.Uint(), 10)
|
||||
if opts.quoted {
|
||||
e.WriteByte('"')
|
||||
}
|
||||
b := e.AvailableBuffer()
|
||||
b = mayAppendQuote(b, opts.quoted)
|
||||
b = strconv.AppendUint(b, v.Uint(), 10)
|
||||
b = mayAppendQuote(b, opts.quoted)
|
||||
e.Write(b)
|
||||
if opts.quoted {
|
||||
e.WriteByte('"')
|
||||
}
|
||||
}
|
||||
|
||||
type floatEncoder int // number of bits
|
||||
@ -582,7 +536,8 @@ func (bits floatEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
// See golang.org/issue/6384 and golang.org/issue/14135.
|
||||
// Like fmt %g, but the exponent cutoffs are different
|
||||
// and exponents themselves are not padded to two digits.
|
||||
b := e.scratch[:0]
|
||||
b := e.AvailableBuffer()
|
||||
b = mayAppendQuote(b, opts.quoted)
|
||||
abs := math.Abs(f)
|
||||
fmt := byte('f')
|
||||
// Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right.
|
||||
@ -600,14 +555,8 @@ func (bits floatEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
b = b[:n-1]
|
||||
}
|
||||
}
|
||||
|
||||
if opts.quoted {
|
||||
e.WriteByte('"')
|
||||
}
|
||||
b = mayAppendQuote(b, opts.quoted)
|
||||
e.Write(b)
|
||||
if opts.quoted {
|
||||
e.WriteByte('"')
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
@ -626,24 +575,18 @@ func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
if !isValidNumber(numStr) {
|
||||
e.error(fmt.Errorf("json: invalid number literal %q", numStr))
|
||||
}
|
||||
if opts.quoted {
|
||||
e.WriteByte('"')
|
||||
}
|
||||
e.WriteString(numStr)
|
||||
if opts.quoted {
|
||||
e.WriteByte('"')
|
||||
}
|
||||
b := e.AvailableBuffer()
|
||||
b = mayAppendQuote(b, opts.quoted)
|
||||
b = append(b, numStr...)
|
||||
b = mayAppendQuote(b, opts.quoted)
|
||||
e.Write(b)
|
||||
return
|
||||
}
|
||||
if opts.quoted {
|
||||
e2 := newEncodeState()
|
||||
// Since we encode the string twice, we only need to escape HTML
|
||||
// the first time.
|
||||
e2.string(v.String(), opts.escapeHTML)
|
||||
e.stringBytes(e2.Bytes(), false)
|
||||
encodeStatePool.Put(e2)
|
||||
b := appendString(nil, v.String(), opts.escapeHTML)
|
||||
e.Write(appendString(e.AvailableBuffer(), b, false)) // no need to escape again since it is already escaped
|
||||
} else {
|
||||
e.string(v.String(), opts.escapeHTML)
|
||||
e.Write(appendString(e.AvailableBuffer(), v.String(), opts.escapeHTML))
|
||||
}
|
||||
}
|
||||
|
||||
@ -724,8 +667,9 @@ type structEncoder struct {
|
||||
}
|
||||
|
||||
type structFields struct {
|
||||
list []field
|
||||
nameIndex map[string]int
|
||||
list []field
|
||||
byExactName map[string]*field
|
||||
byFoldedName map[string]*field
|
||||
}
|
||||
|
||||
func (se structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
@ -793,22 +737,26 @@ func (me mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
|
||||
e.WriteByte('{')
|
||||
|
||||
// Extract and sort the keys.
|
||||
sv := make([]reflectWithString, v.Len())
|
||||
mi := v.MapRange()
|
||||
var (
|
||||
sv = make([]reflectWithString, v.Len())
|
||||
mi = v.MapRange()
|
||||
err error
|
||||
)
|
||||
for i := 0; mi.Next(); i++ {
|
||||
sv[i].k = mi.Key()
|
||||
sv[i].v = mi.Value()
|
||||
if err := sv[i].resolve(); err != nil {
|
||||
if sv[i].ks, err = resolveKeyName(mi.Key()); err != nil {
|
||||
e.error(fmt.Errorf("json: encoding error for type %q: %q", v.Type().String(), err.Error()))
|
||||
}
|
||||
sv[i].v = mi.Value()
|
||||
}
|
||||
sort.Slice(sv, func(i, j int) bool { return sv[i].ks < sv[j].ks })
|
||||
slices.SortFunc(sv, func(i, j reflectWithString) int {
|
||||
return strings.Compare(i.ks, j.ks)
|
||||
})
|
||||
|
||||
for i, kv := range sv {
|
||||
if i > 0 {
|
||||
e.WriteByte(',')
|
||||
}
|
||||
e.string(kv.ks, opts.escapeHTML)
|
||||
e.Write(appendString(e.AvailableBuffer(), kv.ks, opts.escapeHTML))
|
||||
e.WriteByte(':')
|
||||
me.elemEnc(e, kv.v, opts)
|
||||
}
|
||||
@ -835,29 +783,13 @@ func encodeByteSlice(e *encodeState, v reflect.Value, _ encOpts) {
|
||||
e.WriteString("null")
|
||||
return
|
||||
}
|
||||
|
||||
s := v.Bytes()
|
||||
e.WriteByte('"')
|
||||
encodedLen := base64.StdEncoding.EncodedLen(len(s))
|
||||
if encodedLen <= len(e.scratch) {
|
||||
// If the encoded bytes fit in e.scratch, avoid an extra
|
||||
// allocation and use the cheaper Encoding.Encode.
|
||||
dst := e.scratch[:encodedLen]
|
||||
base64.StdEncoding.Encode(dst, s)
|
||||
e.Write(dst)
|
||||
} else if encodedLen <= 1024 {
|
||||
// The encoded bytes are short enough to allocate for, and
|
||||
// Encoding.Encode is still cheaper.
|
||||
dst := make([]byte, encodedLen)
|
||||
base64.StdEncoding.Encode(dst, s)
|
||||
e.Write(dst)
|
||||
} else {
|
||||
// The encoded bytes are too long to cheaply allocate, and
|
||||
// Encoding.Encode is no longer noticeably cheaper.
|
||||
enc := base64.NewEncoder(base64.StdEncoding, e)
|
||||
enc.Write(s)
|
||||
enc.Close()
|
||||
}
|
||||
e.WriteByte('"')
|
||||
b := e.AvailableBuffer()
|
||||
b = append(b, '"')
|
||||
b = base64.StdEncoding.AppendEncode(b, s)
|
||||
b = append(b, '"')
|
||||
e.Write(b)
|
||||
}
|
||||
|
||||
// sliceEncoder just wraps an arrayEncoder, checking to make sure the value isn't nil.
|
||||
@ -997,78 +929,77 @@ func typeByIndex(t reflect.Type, index []int) reflect.Type {
|
||||
}
|
||||
|
||||
type reflectWithString struct {
|
||||
k reflect.Value
|
||||
v reflect.Value
|
||||
ks string
|
||||
}
|
||||
|
||||
func (w *reflectWithString) resolve() error {
|
||||
if w.k.Kind() == reflect.String {
|
||||
w.ks = w.k.String()
|
||||
return nil
|
||||
func resolveKeyName(k reflect.Value) (string, error) {
|
||||
if k.Kind() == reflect.String {
|
||||
return k.String(), nil
|
||||
}
|
||||
if tm, ok := w.k.Interface().(encoding.TextMarshaler); ok {
|
||||
if w.k.Kind() == reflect.Pointer && w.k.IsNil() {
|
||||
return nil
|
||||
if tm, ok := k.Interface().(encoding.TextMarshaler); ok {
|
||||
if k.Kind() == reflect.Pointer && k.IsNil() {
|
||||
return "", nil
|
||||
}
|
||||
buf, err := tm.MarshalText()
|
||||
w.ks = string(buf)
|
||||
return err
|
||||
return string(buf), err
|
||||
}
|
||||
switch w.k.Kind() {
|
||||
switch k.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
w.ks = strconv.FormatInt(w.k.Int(), 10)
|
||||
return nil
|
||||
return strconv.FormatInt(k.Int(), 10), nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
w.ks = strconv.FormatUint(w.k.Uint(), 10)
|
||||
return nil
|
||||
return strconv.FormatUint(k.Uint(), 10), nil
|
||||
}
|
||||
panic("unexpected map key type")
|
||||
}
|
||||
|
||||
// NOTE: keep in sync with stringBytes below.
|
||||
func (e *encodeState) string(s string, escapeHTML bool) {
|
||||
e.WriteByte('"')
|
||||
func appendString[Bytes []byte | string](dst []byte, src Bytes, escapeHTML bool) []byte {
|
||||
dst = append(dst, '"')
|
||||
start := 0
|
||||
for i := 0; i < len(s); {
|
||||
if b := s[i]; b < utf8.RuneSelf {
|
||||
for i := 0; i < len(src); {
|
||||
if b := src[i]; b < utf8.RuneSelf {
|
||||
if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if start < i {
|
||||
e.WriteString(s[start:i])
|
||||
}
|
||||
e.WriteByte('\\')
|
||||
dst = append(dst, src[start:i]...)
|
||||
switch b {
|
||||
case '\\', '"':
|
||||
e.WriteByte(b)
|
||||
dst = append(dst, '\\', b)
|
||||
case '\b':
|
||||
dst = append(dst, '\\', 'b')
|
||||
case '\f':
|
||||
dst = append(dst, '\\', 'f')
|
||||
case '\n':
|
||||
e.WriteByte('n')
|
||||
dst = append(dst, '\\', 'n')
|
||||
case '\r':
|
||||
e.WriteByte('r')
|
||||
dst = append(dst, '\\', 'r')
|
||||
case '\t':
|
||||
e.WriteByte('t')
|
||||
dst = append(dst, '\\', 't')
|
||||
default:
|
||||
// This encodes bytes < 0x20 except for \t, \n and \r.
|
||||
// This encodes bytes < 0x20 except for \b, \f, \n, \r and \t.
|
||||
// If escapeHTML is set, it also escapes <, >, and &
|
||||
// because they can lead to security holes when
|
||||
// user-controlled strings are rendered into JSON
|
||||
// and served to some browsers.
|
||||
e.WriteString(`u00`)
|
||||
e.WriteByte(hex[b>>4])
|
||||
e.WriteByte(hex[b&0xF])
|
||||
dst = append(dst, '\\', 'u', '0', '0', hex[b>>4], hex[b&0xF])
|
||||
}
|
||||
i++
|
||||
start = i
|
||||
continue
|
||||
}
|
||||
c, size := utf8.DecodeRuneInString(s[i:])
|
||||
// TODO(https://go.dev/issue/56948): Use generic utf8 functionality.
|
||||
// For now, cast only a small portion of byte slices to a string
|
||||
// so that it can be stack allocated. This slows down []byte slightly
|
||||
// due to the extra copy, but keeps string performance roughly the same.
|
||||
n := len(src) - i
|
||||
if n > utf8.UTFMax {
|
||||
n = utf8.UTFMax
|
||||
}
|
||||
c, size := utf8.DecodeRuneInString(string(src[i : i+n]))
|
||||
if c == utf8.RuneError && size == 1 {
|
||||
if start < i {
|
||||
e.WriteString(s[start:i])
|
||||
}
|
||||
e.WriteString(`\ufffd`)
|
||||
dst = append(dst, src[start:i]...)
|
||||
dst = append(dst, `\ufffd`...)
|
||||
i += size
|
||||
start = i
|
||||
continue
|
||||
@ -1079,102 +1010,27 @@ func (e *encodeState) string(s string, escapeHTML bool) {
|
||||
// but don't work in JSONP, which has to be evaluated as JavaScript,
|
||||
// and can lead to security holes there. It is valid JSON to
|
||||
// escape them, so we do so unconditionally.
|
||||
// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
|
||||
// See https://en.wikipedia.org/wiki/JSON#Safety.
|
||||
if c == '\u2028' || c == '\u2029' {
|
||||
if start < i {
|
||||
e.WriteString(s[start:i])
|
||||
}
|
||||
e.WriteString(`\u202`)
|
||||
e.WriteByte(hex[c&0xF])
|
||||
dst = append(dst, src[start:i]...)
|
||||
dst = append(dst, '\\', 'u', '2', '0', '2', hex[c&0xF])
|
||||
i += size
|
||||
start = i
|
||||
continue
|
||||
}
|
||||
i += size
|
||||
}
|
||||
if start < len(s) {
|
||||
e.WriteString(s[start:])
|
||||
}
|
||||
e.WriteByte('"')
|
||||
}
|
||||
|
||||
// NOTE: keep in sync with string above.
|
||||
func (e *encodeState) stringBytes(s []byte, escapeHTML bool) {
|
||||
e.WriteByte('"')
|
||||
start := 0
|
||||
for i := 0; i < len(s); {
|
||||
if b := s[i]; b < utf8.RuneSelf {
|
||||
if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if start < i {
|
||||
e.Write(s[start:i])
|
||||
}
|
||||
e.WriteByte('\\')
|
||||
switch b {
|
||||
case '\\', '"':
|
||||
e.WriteByte(b)
|
||||
case '\n':
|
||||
e.WriteByte('n')
|
||||
case '\r':
|
||||
e.WriteByte('r')
|
||||
case '\t':
|
||||
e.WriteByte('t')
|
||||
default:
|
||||
// This encodes bytes < 0x20 except for \t, \n and \r.
|
||||
// If escapeHTML is set, it also escapes <, >, and &
|
||||
// because they can lead to security holes when
|
||||
// user-controlled strings are rendered into JSON
|
||||
// and served to some browsers.
|
||||
e.WriteString(`u00`)
|
||||
e.WriteByte(hex[b>>4])
|
||||
e.WriteByte(hex[b&0xF])
|
||||
}
|
||||
i++
|
||||
start = i
|
||||
continue
|
||||
}
|
||||
c, size := utf8.DecodeRune(s[i:])
|
||||
if c == utf8.RuneError && size == 1 {
|
||||
if start < i {
|
||||
e.Write(s[start:i])
|
||||
}
|
||||
e.WriteString(`\ufffd`)
|
||||
i += size
|
||||
start = i
|
||||
continue
|
||||
}
|
||||
// U+2028 is LINE SEPARATOR.
|
||||
// U+2029 is PARAGRAPH SEPARATOR.
|
||||
// They are both technically valid characters in JSON strings,
|
||||
// but don't work in JSONP, which has to be evaluated as JavaScript,
|
||||
// and can lead to security holes there. It is valid JSON to
|
||||
// escape them, so we do so unconditionally.
|
||||
// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
|
||||
if c == '\u2028' || c == '\u2029' {
|
||||
if start < i {
|
||||
e.Write(s[start:i])
|
||||
}
|
||||
e.WriteString(`\u202`)
|
||||
e.WriteByte(hex[c&0xF])
|
||||
i += size
|
||||
start = i
|
||||
continue
|
||||
}
|
||||
i += size
|
||||
}
|
||||
if start < len(s) {
|
||||
e.Write(s[start:])
|
||||
}
|
||||
e.WriteByte('"')
|
||||
dst = append(dst, src[start:]...)
|
||||
dst = append(dst, '"')
|
||||
return dst
|
||||
}
|
||||
|
||||
// A field represents a single field found in a struct.
|
||||
type field struct {
|
||||
name string
|
||||
nameBytes []byte // []byte(name)
|
||||
equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent
|
||||
nameBytes []byte // []byte(name)
|
||||
|
||||
listIndex int // tracks the index of this field in the list of fields for a struct
|
||||
|
||||
nameNonEsc string // `"` + name + `":`
|
||||
nameEscHTML string // `"` + HTMLEscape(name) + `":`
|
||||
@ -1188,25 +1044,6 @@ type field struct {
|
||||
encoder encoderFunc
|
||||
}
|
||||
|
||||
// byIndex sorts field by index sequence.
|
||||
type byIndex []field
|
||||
|
||||
func (x byIndex) Len() int { return len(x) }
|
||||
|
||||
func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
|
||||
func (x byIndex) Less(i, j int) bool {
|
||||
for k, xik := range x[i].index {
|
||||
if k >= len(x[j].index) {
|
||||
return false
|
||||
}
|
||||
if xik != x[j].index[k] {
|
||||
return xik < x[j].index[k]
|
||||
}
|
||||
}
|
||||
return len(x[i].index) < len(x[j].index)
|
||||
}
|
||||
|
||||
// typeFields returns a list of fields that JSON should recognize for the given type.
|
||||
// The algorithm is breadth-first search over the set of structs to include - the top struct
|
||||
// and then any reachable anonymous structs.
|
||||
@ -1224,8 +1061,8 @@ func typeFields(t reflect.Type) structFields {
|
||||
// Fields found.
|
||||
var fields []field
|
||||
|
||||
// Buffer to run HTMLEscape on field names.
|
||||
var nameEscBuf bytes.Buffer
|
||||
// Buffer to run appendHTMLEscape on field names.
|
||||
var nameEscBuf []byte
|
||||
|
||||
for len(next) > 0 {
|
||||
current, next = next, current[:0]
|
||||
@ -1301,21 +1138,17 @@ func typeFields(t reflect.Type) structFields {
|
||||
quoted: quoted,
|
||||
}
|
||||
field.nameBytes = []byte(field.name)
|
||||
field.equalFold = foldFunc(field.nameBytes)
|
||||
|
||||
// Build nameEscHTML and nameNonEsc ahead of time.
|
||||
nameEscBuf.Reset()
|
||||
nameEscBuf.WriteString(`"`)
|
||||
HTMLEscape(&nameEscBuf, field.nameBytes)
|
||||
nameEscBuf.WriteString(`":`)
|
||||
field.nameEscHTML = nameEscBuf.String()
|
||||
nameEscBuf = appendHTMLEscape(nameEscBuf[:0], field.nameBytes)
|
||||
field.nameEscHTML = `"` + string(nameEscBuf) + `":`
|
||||
field.nameNonEsc = `"` + field.name + `":`
|
||||
|
||||
fields = append(fields, field)
|
||||
if count[f.typ] > 1 {
|
||||
// If there were multiple instances, add a second,
|
||||
// so that the annihilation code will see a duplicate.
|
||||
// It only cares about the distinction between 1 or 2,
|
||||
// It only cares about the distinction between 1 and 2,
|
||||
// so don't bother generating any more copies.
|
||||
fields = append(fields, fields[len(fields)-1])
|
||||
}
|
||||
@ -1331,21 +1164,23 @@ func typeFields(t reflect.Type) structFields {
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(fields, func(i, j int) bool {
|
||||
x := fields
|
||||
slices.SortFunc(fields, func(a, b field) int {
|
||||
// sort field by name, breaking ties with depth, then
|
||||
// breaking ties with "name came from json tag", then
|
||||
// breaking ties with index sequence.
|
||||
if x[i].name != x[j].name {
|
||||
return x[i].name < x[j].name
|
||||
if c := strings.Compare(a.name, b.name); c != 0 {
|
||||
return c
|
||||
}
|
||||
if len(x[i].index) != len(x[j].index) {
|
||||
return len(x[i].index) < len(x[j].index)
|
||||
if c := cmp.Compare(len(a.index), len(b.index)); c != 0 {
|
||||
return c
|
||||
}
|
||||
if x[i].tag != x[j].tag {
|
||||
return x[i].tag
|
||||
if a.tag != b.tag {
|
||||
if a.tag {
|
||||
return -1
|
||||
}
|
||||
return +1
|
||||
}
|
||||
return byIndex(x).Less(i, j)
|
||||
return slices.Compare(a.index, b.index)
|
||||
})
|
||||
|
||||
// Delete all fields that are hidden by the Go rules for embedded fields,
|
||||
@ -1377,17 +1212,25 @@ func typeFields(t reflect.Type) structFields {
|
||||
}
|
||||
|
||||
fields = out
|
||||
sort.Sort(byIndex(fields))
|
||||
slices.SortFunc(fields, func(i, j field) int {
|
||||
return slices.Compare(i.index, j.index)
|
||||
})
|
||||
|
||||
for i := range fields {
|
||||
f := &fields[i]
|
||||
f.encoder = typeEncoder(typeByIndex(t, f.index))
|
||||
}
|
||||
nameIndex := make(map[string]int, len(fields))
|
||||
exactNameIndex := make(map[string]*field, len(fields))
|
||||
foldedNameIndex := make(map[string]*field, len(fields))
|
||||
for i, field := range fields {
|
||||
nameIndex[field.name] = i
|
||||
fields[i].listIndex = i
|
||||
exactNameIndex[field.name] = &fields[i]
|
||||
// For historical reasons, first folded match takes precedence.
|
||||
if _, ok := foldedNameIndex[string(foldName(field.nameBytes))]; !ok {
|
||||
foldedNameIndex[string(foldName(field.nameBytes))] = &fields[i]
|
||||
}
|
||||
}
|
||||
return structFields{fields, nameIndex}
|
||||
return structFields{fields, exactNameIndex, foldedNameIndex}
|
||||
}
|
||||
|
||||
// dominantField looks through the fields, all of which are known to
|
||||
@ -1416,3 +1259,10 @@ func cachedTypeFields(t reflect.Type) structFields {
|
||||
f, _ := fieldCache.LoadOrStore(t, typeFields(t))
|
||||
return f.(structFields)
|
||||
}
|
||||
|
||||
func mayAppendQuote(b []byte, quoted bool) []byte {
|
||||
if quoted {
|
||||
b = append(b, '"')
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
150
vendor/sigs.k8s.io/json/internal/golang/encoding/json/fold.go
generated
vendored
150
vendor/sigs.k8s.io/json/internal/golang/encoding/json/fold.go
generated
vendored
@ -5,140 +5,44 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
caseMask = ^byte(0x20) // Mask to ignore case in ASCII.
|
||||
kelvin = '\u212a'
|
||||
smallLongEss = '\u017f'
|
||||
)
|
||||
|
||||
// foldFunc returns one of four different case folding equivalence
|
||||
// functions, from most general (and slow) to fastest:
|
||||
//
|
||||
// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8
|
||||
// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S')
|
||||
// 3) asciiEqualFold, no special, but includes non-letters (including _)
|
||||
// 4) simpleLetterEqualFold, no specials, no non-letters.
|
||||
//
|
||||
// The letters S and K are special because they map to 3 runes, not just 2:
|
||||
// - S maps to s and to U+017F 'ſ' Latin small letter long s
|
||||
// - k maps to K and to U+212A 'K' Kelvin sign
|
||||
//
|
||||
// See https://play.golang.org/p/tTxjOc0OGo
|
||||
//
|
||||
// The returned function is specialized for matching against s and
|
||||
// should only be given s. It's not curried for performance reasons.
|
||||
func foldFunc(s []byte) func(s, t []byte) bool {
|
||||
nonLetter := false
|
||||
special := false // special letter
|
||||
for _, b := range s {
|
||||
if b >= utf8.RuneSelf {
|
||||
return bytes.EqualFold
|
||||
}
|
||||
upper := b & caseMask
|
||||
if upper < 'A' || upper > 'Z' {
|
||||
nonLetter = true
|
||||
} else if upper == 'K' || upper == 'S' {
|
||||
// See above for why these letters are special.
|
||||
special = true
|
||||
}
|
||||
}
|
||||
if special {
|
||||
return equalFoldRight
|
||||
}
|
||||
if nonLetter {
|
||||
return asciiEqualFold
|
||||
}
|
||||
return simpleLetterEqualFold
|
||||
// foldName returns a folded string such that foldName(x) == foldName(y)
|
||||
// is identical to bytes.EqualFold(x, y).
|
||||
func foldName(in []byte) []byte {
|
||||
// This is inlinable to take advantage of "function outlining".
|
||||
var arr [32]byte // large enough for most JSON names
|
||||
return appendFoldedName(arr[:0], in)
|
||||
}
|
||||
|
||||
// equalFoldRight is a specialization of bytes.EqualFold when s is
|
||||
// known to be all ASCII (including punctuation), but contains an 's',
|
||||
// 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t.
|
||||
// See comments on foldFunc.
|
||||
func equalFoldRight(s, t []byte) bool {
|
||||
for _, sb := range s {
|
||||
if len(t) == 0 {
|
||||
return false
|
||||
}
|
||||
tb := t[0]
|
||||
if tb < utf8.RuneSelf {
|
||||
if sb != tb {
|
||||
sbUpper := sb & caseMask
|
||||
if 'A' <= sbUpper && sbUpper <= 'Z' {
|
||||
if sbUpper != tb&caseMask {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
func appendFoldedName(out, in []byte) []byte {
|
||||
for i := 0; i < len(in); {
|
||||
// Handle single-byte ASCII.
|
||||
if c := in[i]; c < utf8.RuneSelf {
|
||||
if 'a' <= c && c <= 'z' {
|
||||
c -= 'a' - 'A'
|
||||
}
|
||||
t = t[1:]
|
||||
out = append(out, c)
|
||||
i++
|
||||
continue
|
||||
}
|
||||
// sb is ASCII and t is not. t must be either kelvin
|
||||
// sign or long s; sb must be s, S, k, or K.
|
||||
tr, size := utf8.DecodeRune(t)
|
||||
switch sb {
|
||||
case 's', 'S':
|
||||
if tr != smallLongEss {
|
||||
return false
|
||||
}
|
||||
case 'k', 'K':
|
||||
if tr != kelvin {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
t = t[size:]
|
||||
|
||||
// Handle multi-byte Unicode.
|
||||
r, n := utf8.DecodeRune(in[i:])
|
||||
out = utf8.AppendRune(out, foldRune(r))
|
||||
i += n
|
||||
}
|
||||
if len(t) > 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return out
|
||||
}
|
||||
|
||||
// asciiEqualFold is a specialization of bytes.EqualFold for use when
|
||||
// s is all ASCII (but may contain non-letters) and contains no
|
||||
// special-folding letters.
|
||||
// See comments on foldFunc.
|
||||
func asciiEqualFold(s, t []byte) bool {
|
||||
if len(s) != len(t) {
|
||||
return false
|
||||
}
|
||||
for i, sb := range s {
|
||||
tb := t[i]
|
||||
if sb == tb {
|
||||
continue
|
||||
}
|
||||
if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') {
|
||||
if sb&caseMask != tb&caseMask {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
// foldRune is returns the smallest rune for all runes in the same fold set.
|
||||
func foldRune(r rune) rune {
|
||||
for {
|
||||
r2 := unicode.SimpleFold(r)
|
||||
if r2 <= r {
|
||||
return r2
|
||||
}
|
||||
r = r2
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// simpleLetterEqualFold is a specialization of bytes.EqualFold for
|
||||
// use when s is all ASCII letters (no underscores, etc) and also
|
||||
// doesn't contain 'k', 'K', 's', or 'S'.
|
||||
// See comments on foldFunc.
|
||||
func simpleLetterEqualFold(s, t []byte) bool {
|
||||
if len(s) != len(t) {
|
||||
return false
|
||||
}
|
||||
for i, b := range s {
|
||||
if b&caseMask != t[i]&caseMask {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
119
vendor/sigs.k8s.io/json/internal/golang/encoding/json/indent.go
generated
vendored
119
vendor/sigs.k8s.io/json/internal/golang/encoding/json/indent.go
generated
vendored
@ -4,38 +4,67 @@
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
import "bytes"
|
||||
|
||||
// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029
|
||||
// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029
|
||||
// so that the JSON will be safe to embed inside HTML <script> tags.
|
||||
// For historical reasons, web browsers don't honor standard HTML
|
||||
// escaping within <script> tags, so an alternative JSON encoding must be used.
|
||||
func HTMLEscape(dst *bytes.Buffer, src []byte) {
|
||||
dst.Grow(len(src))
|
||||
dst.Write(appendHTMLEscape(dst.AvailableBuffer(), src))
|
||||
}
|
||||
|
||||
func appendHTMLEscape(dst, src []byte) []byte {
|
||||
// The characters can only appear in string literals,
|
||||
// so just scan the string one byte at a time.
|
||||
start := 0
|
||||
for i, c := range src {
|
||||
if c == '<' || c == '>' || c == '&' {
|
||||
dst = append(dst, src[start:i]...)
|
||||
dst = append(dst, '\\', 'u', '0', '0', hex[c>>4], hex[c&0xF])
|
||||
start = i + 1
|
||||
}
|
||||
// Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9).
|
||||
if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 {
|
||||
dst = append(dst, src[start:i]...)
|
||||
dst = append(dst, '\\', 'u', '2', '0', '2', hex[src[i+2]&0xF])
|
||||
start = i + len("\u2029")
|
||||
}
|
||||
}
|
||||
return append(dst, src[start:]...)
|
||||
}
|
||||
|
||||
// Compact appends to dst the JSON-encoded src with
|
||||
// insignificant space characters elided.
|
||||
func Compact(dst *bytes.Buffer, src []byte) error {
|
||||
return compact(dst, src, false)
|
||||
dst.Grow(len(src))
|
||||
b := dst.AvailableBuffer()
|
||||
b, err := appendCompact(b, src, false)
|
||||
dst.Write(b)
|
||||
return err
|
||||
}
|
||||
|
||||
func compact(dst *bytes.Buffer, src []byte, escape bool) error {
|
||||
origLen := dst.Len()
|
||||
func appendCompact(dst, src []byte, escape bool) ([]byte, error) {
|
||||
origLen := len(dst)
|
||||
scan := newScanner()
|
||||
defer freeScanner(scan)
|
||||
start := 0
|
||||
for i, c := range src {
|
||||
if escape && (c == '<' || c == '>' || c == '&') {
|
||||
if start < i {
|
||||
dst.Write(src[start:i])
|
||||
dst = append(dst, src[start:i]...)
|
||||
}
|
||||
dst.WriteString(`\u00`)
|
||||
dst.WriteByte(hex[c>>4])
|
||||
dst.WriteByte(hex[c&0xF])
|
||||
dst = append(dst, '\\', 'u', '0', '0', hex[c>>4], hex[c&0xF])
|
||||
start = i + 1
|
||||
}
|
||||
// Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9).
|
||||
if escape && c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 {
|
||||
if start < i {
|
||||
dst.Write(src[start:i])
|
||||
dst = append(dst, src[start:i]...)
|
||||
}
|
||||
dst.WriteString(`\u202`)
|
||||
dst.WriteByte(hex[src[i+2]&0xF])
|
||||
dst = append(dst, '\\', 'u', '2', '0', '2', hex[src[i+2]&0xF])
|
||||
start = i + 3
|
||||
}
|
||||
v := scan.step(scan, c)
|
||||
@ -44,29 +73,37 @@ func compact(dst *bytes.Buffer, src []byte, escape bool) error {
|
||||
break
|
||||
}
|
||||
if start < i {
|
||||
dst.Write(src[start:i])
|
||||
dst = append(dst, src[start:i]...)
|
||||
}
|
||||
start = i + 1
|
||||
}
|
||||
}
|
||||
if scan.eof() == scanError {
|
||||
dst.Truncate(origLen)
|
||||
return scan.err
|
||||
return dst[:origLen], scan.err
|
||||
}
|
||||
if start < len(src) {
|
||||
dst.Write(src[start:])
|
||||
dst = append(dst, src[start:]...)
|
||||
}
|
||||
return nil
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
|
||||
dst.WriteByte('\n')
|
||||
dst.WriteString(prefix)
|
||||
func appendNewline(dst []byte, prefix, indent string, depth int) []byte {
|
||||
dst = append(dst, '\n')
|
||||
dst = append(dst, prefix...)
|
||||
for i := 0; i < depth; i++ {
|
||||
dst.WriteString(indent)
|
||||
dst = append(dst, indent...)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// indentGrowthFactor specifies the growth factor of indenting JSON input.
|
||||
// Empirically, the growth factor was measured to be between 1.4x to 1.8x
|
||||
// for some set of compacted JSON with the indent being a single tab.
|
||||
// Specify a growth factor slightly larger than what is observed
|
||||
// to reduce probability of allocation in appendIndent.
|
||||
// A factor no higher than 2 ensures that wasted space never exceeds 50%.
|
||||
const indentGrowthFactor = 2
|
||||
|
||||
// Indent appends to dst an indented form of the JSON-encoded src.
|
||||
// Each element in a JSON object or array begins on a new,
|
||||
// indented line beginning with prefix followed by one or more
|
||||
@ -79,7 +116,15 @@ func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
|
||||
// For example, if src has no trailing spaces, neither will dst;
|
||||
// if src ends in a trailing newline, so will dst.
|
||||
func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
|
||||
origLen := dst.Len()
|
||||
dst.Grow(indentGrowthFactor * len(src))
|
||||
b := dst.AvailableBuffer()
|
||||
b, err := appendIndent(b, src, prefix, indent)
|
||||
dst.Write(b)
|
||||
return err
|
||||
}
|
||||
|
||||
func appendIndent(dst, src []byte, prefix, indent string) ([]byte, error) {
|
||||
origLen := len(dst)
|
||||
scan := newScanner()
|
||||
defer freeScanner(scan)
|
||||
needIndent := false
|
||||
@ -96,13 +141,13 @@ func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
|
||||
if needIndent && v != scanEndObject && v != scanEndArray {
|
||||
needIndent = false
|
||||
depth++
|
||||
newline(dst, prefix, indent, depth)
|
||||
dst = appendNewline(dst, prefix, indent, depth)
|
||||
}
|
||||
|
||||
// Emit semantically uninteresting bytes
|
||||
// (in particular, punctuation in strings) unmodified.
|
||||
if v == scanContinue {
|
||||
dst.WriteByte(c)
|
||||
dst = append(dst, c)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -111,33 +156,27 @@ func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
|
||||
case '{', '[':
|
||||
// delay indent so that empty object and array are formatted as {} and [].
|
||||
needIndent = true
|
||||
dst.WriteByte(c)
|
||||
|
||||
dst = append(dst, c)
|
||||
case ',':
|
||||
dst.WriteByte(c)
|
||||
newline(dst, prefix, indent, depth)
|
||||
|
||||
dst = append(dst, c)
|
||||
dst = appendNewline(dst, prefix, indent, depth)
|
||||
case ':':
|
||||
dst.WriteByte(c)
|
||||
dst.WriteByte(' ')
|
||||
|
||||
dst = append(dst, c, ' ')
|
||||
case '}', ']':
|
||||
if needIndent {
|
||||
// suppress indent in empty object/array
|
||||
needIndent = false
|
||||
} else {
|
||||
depth--
|
||||
newline(dst, prefix, indent, depth)
|
||||
dst = appendNewline(dst, prefix, indent, depth)
|
||||
}
|
||||
dst.WriteByte(c)
|
||||
|
||||
dst = append(dst, c)
|
||||
default:
|
||||
dst.WriteByte(c)
|
||||
dst = append(dst, c)
|
||||
}
|
||||
}
|
||||
if scan.eof() == scanError {
|
||||
dst.Truncate(origLen)
|
||||
return scan.err
|
||||
return dst[:origLen], scan.err
|
||||
}
|
||||
return nil
|
||||
return dst, nil
|
||||
}
|
||||
|
4
vendor/sigs.k8s.io/json/internal/golang/encoding/json/scanner.go
generated
vendored
4
vendor/sigs.k8s.io/json/internal/golang/encoding/json/scanner.go
generated
vendored
@ -43,7 +43,7 @@ func checkValid(data []byte, scan *scanner) error {
|
||||
}
|
||||
|
||||
// A SyntaxError is a description of a JSON syntax error.
|
||||
// Unmarshal will return a SyntaxError if the JSON can't be parsed.
|
||||
// [Unmarshal] will return a SyntaxError if the JSON can't be parsed.
|
||||
type SyntaxError struct {
|
||||
msg string // description of error
|
||||
Offset int64 // error occurred after reading Offset bytes
|
||||
@ -594,7 +594,7 @@ func (s *scanner) error(c byte, context string) int {
|
||||
return scanError
|
||||
}
|
||||
|
||||
// quoteChar formats c as a quoted character literal
|
||||
// quoteChar formats c as a quoted character literal.
|
||||
func quoteChar(c byte) string {
|
||||
// special cases - different from quoted strings
|
||||
if c == '\'' {
|
||||
|
41
vendor/sigs.k8s.io/json/internal/golang/encoding/json/stream.go
generated
vendored
41
vendor/sigs.k8s.io/json/internal/golang/encoding/json/stream.go
generated
vendored
@ -32,7 +32,7 @@ func NewDecoder(r io.Reader) *Decoder {
|
||||
}
|
||||
|
||||
// UseNumber causes the Decoder to unmarshal a number into an interface{} as a
|
||||
// Number instead of as a float64.
|
||||
// [Number] instead of as a float64.
|
||||
func (dec *Decoder) UseNumber() { dec.d.useNumber = true }
|
||||
|
||||
// DisallowUnknownFields causes the Decoder to return an error when the destination
|
||||
@ -43,7 +43,7 @@ func (dec *Decoder) DisallowUnknownFields() { dec.d.disallowUnknownFields = true
|
||||
// Decode reads the next JSON-encoded value from its
|
||||
// input and stores it in the value pointed to by v.
|
||||
//
|
||||
// See the documentation for Unmarshal for details about
|
||||
// See the documentation for [Unmarshal] for details about
|
||||
// the conversion of JSON into a Go value.
|
||||
func (dec *Decoder) Decode(v any) error {
|
||||
if dec.err != nil {
|
||||
@ -78,7 +78,7 @@ func (dec *Decoder) Decode(v any) error {
|
||||
}
|
||||
|
||||
// Buffered returns a reader of the data remaining in the Decoder's
|
||||
// buffer. The reader is valid until the next call to Decode.
|
||||
// buffer. The reader is valid until the next call to [Decoder.Decode].
|
||||
func (dec *Decoder) Buffered() io.Reader {
|
||||
return bytes.NewReader(dec.buf[dec.scanp:])
|
||||
}
|
||||
@ -182,7 +182,7 @@ type Encoder struct {
|
||||
err error
|
||||
escapeHTML bool
|
||||
|
||||
indentBuf *bytes.Buffer
|
||||
indentBuf []byte
|
||||
indentPrefix string
|
||||
indentValue string
|
||||
}
|
||||
@ -193,15 +193,19 @@ func NewEncoder(w io.Writer) *Encoder {
|
||||
}
|
||||
|
||||
// Encode writes the JSON encoding of v to the stream,
|
||||
// with insignificant space characters elided,
|
||||
// followed by a newline character.
|
||||
//
|
||||
// See the documentation for Marshal for details about the
|
||||
// See the documentation for [Marshal] for details about the
|
||||
// conversion of Go values to JSON.
|
||||
func (enc *Encoder) Encode(v any) error {
|
||||
if enc.err != nil {
|
||||
return enc.err
|
||||
}
|
||||
|
||||
e := newEncodeState()
|
||||
defer encodeStatePool.Put(e)
|
||||
|
||||
err := e.marshal(v, encOpts{escapeHTML: enc.escapeHTML})
|
||||
if err != nil {
|
||||
return err
|
||||
@ -217,20 +221,15 @@ func (enc *Encoder) Encode(v any) error {
|
||||
|
||||
b := e.Bytes()
|
||||
if enc.indentPrefix != "" || enc.indentValue != "" {
|
||||
if enc.indentBuf == nil {
|
||||
enc.indentBuf = new(bytes.Buffer)
|
||||
}
|
||||
enc.indentBuf.Reset()
|
||||
err = Indent(enc.indentBuf, b, enc.indentPrefix, enc.indentValue)
|
||||
enc.indentBuf, err = appendIndent(enc.indentBuf[:0], b, enc.indentPrefix, enc.indentValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b = enc.indentBuf.Bytes()
|
||||
b = enc.indentBuf
|
||||
}
|
||||
if _, err = enc.w.Write(b); err != nil {
|
||||
enc.err = err
|
||||
}
|
||||
encodeStatePool.Put(e)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -255,7 +254,7 @@ func (enc *Encoder) SetEscapeHTML(on bool) {
|
||||
|
||||
/*
|
||||
// RawMessage is a raw encoded JSON value.
|
||||
// It implements Marshaler and Unmarshaler and can
|
||||
// It implements [Marshaler] and [Unmarshaler] and can
|
||||
// be used to delay JSON decoding or precompute a JSON encoding.
|
||||
type RawMessage []byte
|
||||
|
||||
@ -283,12 +282,12 @@ var _ Unmarshaler = (*RawMessage)(nil)
|
||||
/*
|
||||
// A Token holds a value of one of these types:
|
||||
//
|
||||
// Delim, for the four JSON delimiters [ ] { }
|
||||
// bool, for JSON booleans
|
||||
// float64, for JSON numbers
|
||||
// Number, for JSON numbers
|
||||
// string, for JSON string literals
|
||||
// nil, for JSON null
|
||||
// - [Delim], for the four JSON delimiters [ ] { }
|
||||
// - bool, for JSON booleans
|
||||
// - float64, for JSON numbers
|
||||
// - [Number], for JSON numbers
|
||||
// - string, for JSON string literals
|
||||
// - nil, for JSON null
|
||||
type Token any
|
||||
*/
|
||||
|
||||
@ -361,14 +360,14 @@ func (d Delim) String() string {
|
||||
*/
|
||||
|
||||
// Token returns the next JSON token in the input stream.
|
||||
// At the end of the input stream, Token returns nil, io.EOF.
|
||||
// At the end of the input stream, Token returns nil, [io.EOF].
|
||||
//
|
||||
// Token guarantees that the delimiters [ ] { } it returns are
|
||||
// properly nested and matched: if Token encounters an unexpected
|
||||
// delimiter in the input, it will return an error.
|
||||
//
|
||||
// The input stream consists of basic JSON values—bool, string,
|
||||
// number, and null—along with delimiters [ ] { } of type Delim
|
||||
// number, and null—along with delimiters [ ] { } of type [Delim]
|
||||
// to mark the start and end of arrays and objects.
|
||||
// Commas and colons are elided.
|
||||
func (dec *Decoder) Token() (Token, error) {
|
||||
|
277
vendor/sigs.k8s.io/structured-merge-diff/v4/fieldpath/set.go
generated
vendored
277
vendor/sigs.k8s.io/structured-merge-diff/v4/fieldpath/set.go
generated
vendored
@ -17,6 +17,8 @@ limitations under the License.
|
||||
package fieldpath
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/value"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@ -136,6 +138,198 @@ func (s *Set) EnsureNamedFieldsAreMembers(sc *schema.Schema, tr schema.TypeRef)
|
||||
}
|
||||
}
|
||||
|
||||
// MakePrefixMatcherOrDie is the same as PrefixMatcher except it panics if parts can't be
|
||||
// turned into a SetMatcher.
|
||||
func MakePrefixMatcherOrDie(parts ...interface{}) *SetMatcher {
|
||||
result, err := PrefixMatcher(parts...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// PrefixMatcher creates a SetMatcher that matches all field paths prefixed by the given list of matcher path parts.
|
||||
// The matcher parts may any of:
|
||||
//
|
||||
// - PathElementMatcher - for wildcards, `MatchAnyPathElement()` can be used as well.
|
||||
// - PathElement - for any path element
|
||||
// - value.FieldList - for listMap keys
|
||||
// - value.Value - for scalar list elements
|
||||
// - string - For field names
|
||||
// - int - for array indices
|
||||
func PrefixMatcher(parts ...interface{}) (*SetMatcher, error) {
|
||||
current := MatchAnySet() // match all field path suffixes
|
||||
for i := len(parts) - 1; i >= 0; i-- {
|
||||
part := parts[i]
|
||||
var pattern PathElementMatcher
|
||||
switch t := part.(type) {
|
||||
case PathElementMatcher:
|
||||
// any path matcher, including wildcard
|
||||
pattern = t
|
||||
case PathElement:
|
||||
// any path element
|
||||
pattern = PathElementMatcher{PathElement: t}
|
||||
case *value.FieldList:
|
||||
// a listMap key
|
||||
if len(*t) == 0 {
|
||||
return nil, fmt.Errorf("associative list key type path elements must have at least one key (got zero)")
|
||||
}
|
||||
pattern = PathElementMatcher{PathElement: PathElement{Key: t}}
|
||||
case value.Value:
|
||||
// a scalar or set-type list element
|
||||
pattern = PathElementMatcher{PathElement: PathElement{Value: &t}}
|
||||
case string:
|
||||
// a plain field name
|
||||
pattern = PathElementMatcher{PathElement: PathElement{FieldName: &t}}
|
||||
case int:
|
||||
// a plain list index
|
||||
pattern = PathElementMatcher{PathElement: PathElement{Index: &t}}
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected type %T", t)
|
||||
}
|
||||
current = &SetMatcher{
|
||||
members: []*SetMemberMatcher{{
|
||||
Path: pattern,
|
||||
Child: current,
|
||||
}},
|
||||
}
|
||||
}
|
||||
return current, nil
|
||||
}
|
||||
|
||||
// MatchAnyPathElement returns a PathElementMatcher that matches any path element.
|
||||
func MatchAnyPathElement() PathElementMatcher {
|
||||
return PathElementMatcher{Wildcard: true}
|
||||
}
|
||||
|
||||
// MatchAnySet returns a SetMatcher that matches any set.
|
||||
func MatchAnySet() *SetMatcher {
|
||||
return &SetMatcher{wildcard: true}
|
||||
}
|
||||
|
||||
// NewSetMatcher returns a new SetMatcher.
|
||||
// Wildcard members take precedent over non-wildcard members;
|
||||
// all non-wildcard members are ignored if there is a wildcard members.
|
||||
func NewSetMatcher(wildcard bool, members ...*SetMemberMatcher) *SetMatcher {
|
||||
sort.Sort(sortedMemberMatcher(members))
|
||||
return &SetMatcher{wildcard: wildcard, members: members}
|
||||
}
|
||||
|
||||
// SetMatcher defines a matcher that matches fields in a Set.
|
||||
// SetMatcher is structured much like a Set but with wildcard support.
|
||||
type SetMatcher struct {
|
||||
// wildcard indicates that all members and children are included in the match.
|
||||
// If set, the members field is ignored.
|
||||
wildcard bool
|
||||
// members provides patterns to match the members of a Set.
|
||||
// Wildcard members are sorted before non-wildcards and take precedent over
|
||||
// non-wildcard members.
|
||||
members sortedMemberMatcher
|
||||
}
|
||||
|
||||
type sortedMemberMatcher []*SetMemberMatcher
|
||||
|
||||
func (s sortedMemberMatcher) Len() int { return len(s) }
|
||||
func (s sortedMemberMatcher) Less(i, j int) bool { return s[i].Path.Less(s[j].Path) }
|
||||
func (s sortedMemberMatcher) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
func (s sortedMemberMatcher) Find(p PathElementMatcher) (location int, ok bool) {
|
||||
return sort.Find(len(s), func(i int) int {
|
||||
return s[i].Path.Compare(p)
|
||||
})
|
||||
}
|
||||
|
||||
// Merge merges s and s2 and returns a SetMatcher that matches all field paths matched by either s or s2.
|
||||
// During the merge, members of s and s2 with the same PathElementMatcher merged into a single member
|
||||
// with the children of each merged by calling this function recursively.
|
||||
func (s *SetMatcher) Merge(s2 *SetMatcher) *SetMatcher {
|
||||
if s.wildcard || s2.wildcard {
|
||||
return NewSetMatcher(true)
|
||||
}
|
||||
merged := make(sortedMemberMatcher, len(s.members), len(s.members)+len(s2.members))
|
||||
copy(merged, s.members)
|
||||
for _, m := range s2.members {
|
||||
if i, ok := s.members.Find(m.Path); ok {
|
||||
// since merged is a shallow copy, do not modify elements in place
|
||||
merged[i] = &SetMemberMatcher{
|
||||
Path: merged[i].Path,
|
||||
Child: merged[i].Child.Merge(m.Child),
|
||||
}
|
||||
} else {
|
||||
merged = append(merged, m)
|
||||
}
|
||||
}
|
||||
return NewSetMatcher(false, merged...) // sort happens here
|
||||
}
|
||||
|
||||
// SetMemberMatcher defines a matcher that matches the members of a Set.
|
||||
// SetMemberMatcher is structured much like the elements of a SetNodeMap, but
|
||||
// with wildcard support.
|
||||
type SetMemberMatcher struct {
|
||||
// Path provides a matcher to match members of a Set.
|
||||
// If Path is a wildcard, all members of a Set are included in the match.
|
||||
// Otherwise, if any Path is Equal to a member of a Set, that member is
|
||||
// included in the match and the children of that member are matched
|
||||
// against the Child matcher.
|
||||
Path PathElementMatcher
|
||||
|
||||
// Child provides a matcher to use for the children of matched members of a Set.
|
||||
Child *SetMatcher
|
||||
}
|
||||
|
||||
// PathElementMatcher defined a path matcher for a PathElement.
|
||||
type PathElementMatcher struct {
|
||||
// Wildcard indicates that all PathElements are matched by this matcher.
|
||||
// If set, PathElement is ignored.
|
||||
Wildcard bool
|
||||
|
||||
// PathElement indicates that a PathElement is matched if it is Equal
|
||||
// to this PathElement.
|
||||
PathElement
|
||||
}
|
||||
|
||||
func (p PathElementMatcher) Equals(p2 PathElementMatcher) bool {
|
||||
return p.Wildcard != p2.Wildcard && p.PathElement.Equals(p2.PathElement)
|
||||
}
|
||||
|
||||
func (p PathElementMatcher) Less(p2 PathElementMatcher) bool {
|
||||
if p.Wildcard && !p2.Wildcard {
|
||||
return true
|
||||
} else if p2.Wildcard {
|
||||
return false
|
||||
}
|
||||
return p.PathElement.Less(p2.PathElement)
|
||||
}
|
||||
|
||||
func (p PathElementMatcher) Compare(p2 PathElementMatcher) int {
|
||||
if p.Wildcard && !p2.Wildcard {
|
||||
return -1
|
||||
} else if p2.Wildcard {
|
||||
return 1
|
||||
}
|
||||
return p.PathElement.Compare(p2.PathElement)
|
||||
}
|
||||
|
||||
// FilterIncludeMatches returns a Set with only the field paths that match.
|
||||
func (s *Set) FilterIncludeMatches(pattern *SetMatcher) *Set {
|
||||
if pattern.wildcard {
|
||||
return s
|
||||
}
|
||||
|
||||
members := PathElementSet{}
|
||||
for _, m := range s.Members.members {
|
||||
for _, pm := range pattern.members {
|
||||
if pm.Path.Wildcard || pm.Path.PathElement.Equals(m) {
|
||||
members.Insert(m)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return &Set{
|
||||
Members: members,
|
||||
Children: *s.Children.FilterIncludeMatches(pattern),
|
||||
}
|
||||
}
|
||||
|
||||
// Size returns the number of members of the set.
|
||||
func (s *Set) Size() int {
|
||||
return s.Members.Size() + s.Children.Size()
|
||||
@ -476,6 +670,33 @@ func (s *SetNodeMap) EnsureNamedFieldsAreMembers(sc *schema.Schema, tr schema.Ty
|
||||
}
|
||||
}
|
||||
|
||||
// FilterIncludeMatches returns a SetNodeMap with only the field paths that match the matcher.
|
||||
func (s *SetNodeMap) FilterIncludeMatches(pattern *SetMatcher) *SetNodeMap {
|
||||
if pattern.wildcard {
|
||||
return s
|
||||
}
|
||||
|
||||
var out sortedSetNode
|
||||
for _, member := range s.members {
|
||||
for _, c := range pattern.members {
|
||||
if c.Path.Wildcard || c.Path.PathElement.Equals(member.pathElement) {
|
||||
childSet := member.set.FilterIncludeMatches(c.Child)
|
||||
if childSet.Size() > 0 {
|
||||
out = append(out, setNode{
|
||||
pathElement: member.pathElement,
|
||||
set: childSet,
|
||||
})
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &SetNodeMap{
|
||||
members: out,
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate calls f for each PathElement in the set.
|
||||
func (s *SetNodeMap) Iterate(f func(PathElement)) {
|
||||
for _, n := range s.members {
|
||||
@ -503,3 +724,59 @@ func (s *SetNodeMap) Leaves() *SetNodeMap {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Filter defines an interface for excluding field paths from a set.
|
||||
// NewExcludeSetFilter can be used to create a filter that removes
|
||||
// specific field paths and all of their children.
|
||||
// NewIncludeMatcherFilter can be used to create a filter that removes all fields except
|
||||
// the fields that match a field path matcher. PrefixMatcher and MakePrefixMatcherOrDie
|
||||
// can be used to define field path patterns.
|
||||
type Filter interface {
|
||||
// Filter returns a filtered copy of the set.
|
||||
Filter(*Set) *Set
|
||||
}
|
||||
|
||||
// NewExcludeSetFilter returns a filter that removes field paths in the exclude set.
|
||||
func NewExcludeSetFilter(exclude *Set) Filter {
|
||||
return excludeFilter{exclude}
|
||||
}
|
||||
|
||||
// NewExcludeFilterSetMap converts a map of APIVersion to exclude set to a map of APIVersion to exclude filters.
|
||||
func NewExcludeFilterSetMap(resetFields map[APIVersion]*Set) map[APIVersion]Filter {
|
||||
result := make(map[APIVersion]Filter)
|
||||
for k, v := range resetFields {
|
||||
result[k] = excludeFilter{v}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
type excludeFilter struct {
|
||||
excludeSet *Set
|
||||
}
|
||||
|
||||
func (t excludeFilter) Filter(set *Set) *Set {
|
||||
return set.RecursiveDifference(t.excludeSet)
|
||||
}
|
||||
|
||||
// NewIncludeMatcherFilter returns a filter that only includes field paths that match.
|
||||
// If no matchers are provided, the filter includes all field paths.
|
||||
// PrefixMatcher and MakePrefixMatcherOrDie can help create basic matcher.
|
||||
func NewIncludeMatcherFilter(matchers ...*SetMatcher) Filter {
|
||||
if len(matchers) == 0 {
|
||||
return includeMatcherFilter{&SetMatcher{wildcard: true}}
|
||||
}
|
||||
matcher := matchers[0]
|
||||
for i := 1; i < len(matchers); i++ {
|
||||
matcher = matcher.Merge(matchers[i])
|
||||
}
|
||||
|
||||
return includeMatcherFilter{matcher}
|
||||
}
|
||||
|
||||
type includeMatcherFilter struct {
|
||||
matcher *SetMatcher
|
||||
}
|
||||
|
||||
func (pf includeMatcherFilter) Filter(set *Set) *Set {
|
||||
return set.FilterIncludeMatches(pf.matcher)
|
||||
}
|
||||
|
34
vendor/sigs.k8s.io/structured-merge-diff/v4/merge/update.go
generated
vendored
34
vendor/sigs.k8s.io/structured-merge-diff/v4/merge/update.go
generated
vendored
@ -15,7 +15,6 @@ package merge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/typed"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/value"
|
||||
@ -31,8 +30,8 @@ type Converter interface {
|
||||
// UpdateBuilder allows you to create a new Updater by exposing all of
|
||||
// the options and setting them once.
|
||||
type UpdaterBuilder struct {
|
||||
Converter Converter
|
||||
IgnoredFields map[fieldpath.APIVersion]*fieldpath.Set
|
||||
Converter Converter
|
||||
IgnoreFilter map[fieldpath.APIVersion]fieldpath.Filter
|
||||
|
||||
// Stop comparing the new object with old object after applying.
|
||||
// This was initially used to avoid spurious etcd update, but
|
||||
@ -46,7 +45,7 @@ type UpdaterBuilder struct {
|
||||
func (u *UpdaterBuilder) BuildUpdater() *Updater {
|
||||
return &Updater{
|
||||
Converter: u.Converter,
|
||||
IgnoredFields: u.IgnoredFields,
|
||||
IgnoreFilter: u.IgnoreFilter,
|
||||
returnInputOnNoop: u.ReturnInputOnNoop,
|
||||
}
|
||||
}
|
||||
@ -58,7 +57,7 @@ type Updater struct {
|
||||
Converter Converter
|
||||
|
||||
// Deprecated: This will eventually become private.
|
||||
IgnoredFields map[fieldpath.APIVersion]*fieldpath.Set
|
||||
IgnoreFilter map[fieldpath.APIVersion]fieldpath.Filter
|
||||
|
||||
returnInputOnNoop bool
|
||||
}
|
||||
@ -72,7 +71,7 @@ func (s *Updater) update(oldObject, newObject *typed.TypedValue, version fieldpa
|
||||
}
|
||||
|
||||
versions := map[fieldpath.APIVersion]*typed.Comparison{
|
||||
version: compare.ExcludeFields(s.IgnoredFields[version]),
|
||||
version: compare.FilterFields(s.IgnoreFilter[version]),
|
||||
}
|
||||
|
||||
for manager, managerSet := range managers {
|
||||
@ -102,7 +101,7 @@ func (s *Updater) update(oldObject, newObject *typed.TypedValue, version fieldpa
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to compare objects: %v", err)
|
||||
}
|
||||
versions[managerSet.APIVersion()] = compare.ExcludeFields(s.IgnoredFields[managerSet.APIVersion()])
|
||||
versions[managerSet.APIVersion()] = compare.FilterFields(s.IgnoreFilter[managerSet.APIVersion()])
|
||||
}
|
||||
|
||||
conflictSet := managerSet.Set().Intersection(compare.Modified.Union(compare.Added))
|
||||
@ -154,13 +153,14 @@ func (s *Updater) Update(liveObject, newObject *typed.TypedValue, version fieldp
|
||||
if _, ok := managers[manager]; !ok {
|
||||
managers[manager] = fieldpath.NewVersionedSet(fieldpath.NewSet(), version, false)
|
||||
}
|
||||
|
||||
ignored := s.IgnoredFields[version]
|
||||
if ignored == nil {
|
||||
ignored = fieldpath.NewSet()
|
||||
set := managers[manager].Set().Difference(compare.Removed).Union(compare.Modified).Union(compare.Added)
|
||||
ignoreFilter := s.IgnoreFilter[version]
|
||||
if ignoreFilter != nil {
|
||||
set = ignoreFilter.Filter(set)
|
||||
}
|
||||
|
||||
managers[manager] = fieldpath.NewVersionedSet(
|
||||
managers[manager].Set().Difference(compare.Removed).Union(compare.Modified).Union(compare.Added).RecursiveDifference(ignored),
|
||||
set,
|
||||
version,
|
||||
false,
|
||||
)
|
||||
@ -189,13 +189,9 @@ func (s *Updater) Apply(liveObject, configObject *typed.TypedValue, version fiel
|
||||
return nil, fieldpath.ManagedFields{}, fmt.Errorf("failed to get field set: %v", err)
|
||||
}
|
||||
|
||||
ignored := s.IgnoredFields[version]
|
||||
if ignored != nil {
|
||||
set = set.RecursiveDifference(ignored)
|
||||
// TODO: is this correct. If we don't remove from lastSet pruning might remove the fields?
|
||||
if lastSet != nil {
|
||||
lastSet.Set().RecursiveDifference(ignored)
|
||||
}
|
||||
ignoreFilter := s.IgnoreFilter[version]
|
||||
if ignoreFilter != nil {
|
||||
set = ignoreFilter.Filter(set)
|
||||
}
|
||||
managers[manager] = fieldpath.NewVersionedSet(set, version, true)
|
||||
newObject, err = s.prune(newObject, managers, manager, lastSet)
|
||||
|
10
vendor/sigs.k8s.io/structured-merge-diff/v4/typed/compare.go
generated
vendored
10
vendor/sigs.k8s.io/structured-merge-diff/v4/typed/compare.go
generated
vendored
@ -72,6 +72,16 @@ func (c *Comparison) ExcludeFields(fields *fieldpath.Set) *Comparison {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Comparison) FilterFields(filter fieldpath.Filter) *Comparison {
|
||||
if filter == nil {
|
||||
return c
|
||||
}
|
||||
c.Removed = filter.Filter(c.Removed)
|
||||
c.Modified = filter.Filter(c.Modified)
|
||||
c.Added = filter.Filter(c.Added)
|
||||
return c
|
||||
}
|
||||
|
||||
type compareWalker struct {
|
||||
lhs value.Value
|
||||
rhs value.Value
|
||||
|
2
vendor/sigs.k8s.io/structured-merge-diff/v4/typed/parser.go
generated
vendored
2
vendor/sigs.k8s.io/structured-merge-diff/v4/typed/parser.go
generated
vendored
@ -19,9 +19,9 @@ package typed
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/schema"
|
||||
"sigs.k8s.io/structured-merge-diff/v4/value"
|
||||
yaml "sigs.k8s.io/yaml/goyaml.v2"
|
||||
)
|
||||
|
||||
// YAMLObject is an object encoded in YAML.
|
||||
|
63
vendor/sigs.k8s.io/structured-merge-diff/v4/value/reflectcache.go
generated
vendored
63
vendor/sigs.k8s.io/structured-merge-diff/v4/value/reflectcache.go
generated
vendored
@ -19,7 +19,9 @@ package value
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
@ -184,6 +186,11 @@ func (e TypeReflectCacheEntry) ToUnstructured(sv reflect.Value) (interface{}, er
|
||||
// This is based on https://github.com/kubernetes/kubernetes/blob/82c9e5c814eb7acc6cc0a090c057294d0667ad66/staging/src/k8s.io/apimachinery/pkg/runtime/converter.go#L505
|
||||
// and is intended to replace it.
|
||||
|
||||
// Check if the object is a nil pointer.
|
||||
if sv.Kind() == reflect.Ptr && sv.IsNil() {
|
||||
// We're done - we don't need to store anything.
|
||||
return nil, nil
|
||||
}
|
||||
// Check if the object has a custom string converter and use it if available, since it is much more efficient
|
||||
// than round tripping through json.
|
||||
if converter, ok := e.getUnstructuredConverter(sv); ok {
|
||||
@ -191,11 +198,6 @@ func (e TypeReflectCacheEntry) ToUnstructured(sv reflect.Value) (interface{}, er
|
||||
}
|
||||
// Check if the object has a custom JSON marshaller/unmarshaller.
|
||||
if marshaler, ok := e.getJsonMarshaler(sv); ok {
|
||||
if sv.Kind() == reflect.Ptr && sv.IsNil() {
|
||||
// We're done - we don't need to store anything.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
data, err := marshaler.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -379,36 +381,49 @@ const maxDepth = 10000
|
||||
// unmarshal unmarshals the given data
|
||||
// If v is a *map[string]interface{}, numbers are converted to int64 or float64
|
||||
func unmarshal(data []byte, v interface{}) error {
|
||||
// Build a decoder from the given data
|
||||
decoder := json.NewDecoder(bytes.NewBuffer(data))
|
||||
// Preserve numbers, rather than casting to float64 automatically
|
||||
decoder.UseNumber()
|
||||
// Run the decode
|
||||
if err := decoder.Decode(v); err != nil {
|
||||
return err
|
||||
}
|
||||
next := decoder.InputOffset()
|
||||
if _, err := decoder.Token(); !errors.Is(err, io.EOF) {
|
||||
tail := bytes.TrimLeft(data[next:], " \t\r\n")
|
||||
return fmt.Errorf("unexpected trailing data at offset %d", len(data)-len(tail))
|
||||
}
|
||||
|
||||
// If the decode succeeds, post-process the object to convert json.Number objects to int64 or float64
|
||||
switch v := v.(type) {
|
||||
case *map[string]interface{}:
|
||||
// Build a decoder from the given data
|
||||
decoder := json.NewDecoder(bytes.NewBuffer(data))
|
||||
// Preserve numbers, rather than casting to float64 automatically
|
||||
decoder.UseNumber()
|
||||
// Run the decode
|
||||
if err := decoder.Decode(v); err != nil {
|
||||
return err
|
||||
}
|
||||
// If the decode succeeds, post-process the map to convert json.Number objects to int64 or float64
|
||||
return convertMapNumbers(*v, 0)
|
||||
|
||||
case *[]interface{}:
|
||||
// Build a decoder from the given data
|
||||
decoder := json.NewDecoder(bytes.NewBuffer(data))
|
||||
// Preserve numbers, rather than casting to float64 automatically
|
||||
decoder.UseNumber()
|
||||
// Run the decode
|
||||
if err := decoder.Decode(v); err != nil {
|
||||
return err
|
||||
}
|
||||
// If the decode succeeds, post-process the map to convert json.Number objects to int64 or float64
|
||||
return convertSliceNumbers(*v, 0)
|
||||
|
||||
case *interface{}:
|
||||
return convertInterfaceNumbers(v, 0)
|
||||
|
||||
default:
|
||||
return json.Unmarshal(data, v)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func convertInterfaceNumbers(v *interface{}, depth int) error {
|
||||
var err error
|
||||
switch v2 := (*v).(type) {
|
||||
case json.Number:
|
||||
*v, err = convertNumber(v2)
|
||||
case map[string]interface{}:
|
||||
err = convertMapNumbers(v2, depth+1)
|
||||
case []interface{}:
|
||||
err = convertSliceNumbers(v2, depth+1)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// convertMapNumbers traverses the map, converting any json.Number values to int64 or float64.
|
||||
// values which are map[string]interface{} or []interface{} are recursively visited
|
||||
func convertMapNumbers(m map[string]interface{}, depth int) error {
|
||||
|
2
vendor/sigs.k8s.io/structured-merge-diff/v4/value/value.go
generated
vendored
2
vendor/sigs.k8s.io/structured-merge-diff/v4/value/value.go
generated
vendored
@ -23,7 +23,7 @@ import (
|
||||
"strings"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"gopkg.in/yaml.v2"
|
||||
yaml "sigs.k8s.io/yaml/goyaml.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
|
Reference in New Issue
Block a user