github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/k8s/encoder.go (about)

     1  package k8s
     2  
     3  import (
     4  	"unsafe"
     5  
     6  	jsoniter "github.com/json-iterator/go"
     7  	"github.com/modern-go/reflect2"
     8  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     9  	"k8s.io/client-go/kubernetes/scheme"
    10  )
    11  
    12  var defaultJSONIterator = createDefaultJSONIterator()
    13  var specJSONIterator = createSpecJSONIterator()
    14  
    15  func createDefaultJSONConfig() jsoniter.Config {
    16  	return jsoniter.Config{
    17  		EscapeHTML:             true,
    18  		SortMapKeys:            true,
    19  		ValidateJsonRawMessage: true,
    20  		CaseSensitive:          true,
    21  	}
    22  }
    23  
    24  func createDefaultJSONIterator() jsoniter.API {
    25  	return createDefaultJSONConfig().Froze()
    26  }
    27  
    28  // Create a JSON iterator that:
    29  // - encodes "zero" metav1.Time values as empty instead of nil
    30  // - encodes all status values as empty
    31  func createSpecJSONIterator() jsoniter.API {
    32  	config := createDefaultJSONConfig().Froze()
    33  	config.RegisterExtension(newTimeExtension())
    34  	config.RegisterExtension(alwaysEmptyExtension{
    35  		typeIndex: createTypeIndex(allStatusTypes()),
    36  	})
    37  	return config
    38  }
    39  
    40  func allStatusTypes() []reflect2.Type {
    41  	result := []reflect2.Type{}
    42  	for _, typ := range scheme.Scheme.AllKnownTypes() {
    43  		typ2 := reflect2.Type2(typ)
    44  
    45  		sTyp2, ok := typ2.(reflect2.StructType)
    46  		if !ok {
    47  			continue
    48  		}
    49  
    50  		statusField := sTyp2.FieldByName("Status")
    51  		if statusField == nil {
    52  			continue
    53  		}
    54  
    55  		result = append(result, statusField.Type())
    56  	}
    57  	return result
    58  }
    59  
    60  type TypeIndex map[reflect2.Type]bool
    61  
    62  func (idx TypeIndex) Contains(typ reflect2.Type) bool {
    63  	_, ok := idx[typ]
    64  	return ok
    65  }
    66  
    67  func createTypeIndex(ts []reflect2.Type) TypeIndex {
    68  	result := make(map[reflect2.Type]bool)
    69  	for _, t := range ts {
    70  		result[t] = true
    71  	}
    72  	return TypeIndex(result)
    73  }
    74  
    75  // Any type that matches this extension is considered empty,
    76  // and skipped during json serialization.
    77  type alwaysEmptyExtension struct {
    78  	*jsoniter.DummyExtension
    79  	typeIndex TypeIndex
    80  }
    81  
    82  func (e alwaysEmptyExtension) CreateEncoder(typ reflect2.Type) jsoniter.ValEncoder {
    83  	if e.typeIndex.Contains(typ) {
    84  		return alwaysEmptyEncoder{}
    85  	}
    86  	return nil
    87  }
    88  
    89  type alwaysEmptyEncoder struct {
    90  }
    91  
    92  func (alwaysEmptyEncoder) IsEmpty(ptr unsafe.Pointer) bool                    { return true }
    93  func (alwaysEmptyEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {}
    94  
    95  type timeExtension struct {
    96  	*jsoniter.DummyExtension
    97  	timeType reflect2.Type
    98  }
    99  
   100  func newTimeExtension() timeExtension {
   101  	return timeExtension{
   102  		// memoize the type lookup
   103  		timeType: reflect2.TypeOf(metav1.Time{}),
   104  	}
   105  }
   106  
   107  func (e timeExtension) CreateEncoder(typ reflect2.Type) jsoniter.ValEncoder {
   108  	if e.timeType == typ {
   109  		return timeEncoder{delegate: defaultJSONIterator.EncoderOf(typ)}
   110  	}
   111  	return nil
   112  }
   113  
   114  type timeEncoder struct {
   115  	delegate jsoniter.ValEncoder
   116  }
   117  
   118  // Returns true if the time value is the zero value.
   119  func (e timeEncoder) IsEmpty(ptr unsafe.Pointer) bool {
   120  	t := *((*metav1.Time)(ptr))
   121  	return t == metav1.Time{} || e.delegate.IsEmpty(ptr)
   122  }
   123  
   124  func (e timeEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
   125  	e.delegate.Encode(ptr, stream)
   126  }