github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/runtime/serializer/recognizer/recognizer.go (about)

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package recognizer
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime"
    23  	"github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/runtime/schema"
    24  )
    25  
    26  type RecognizingDecoder interface {
    27  	runtime.Decoder
    28  	// RecognizesData should return true if the input provided in the provided reader
    29  	// belongs to this decoder, or an error if the data could not be read or is ambiguous.
    30  	// Unknown is true if the data could not be determined to match the decoder type.
    31  	// Decoders should assume that they can read as much of peek as they need (as the caller
    32  	// provides) and may return unknown if the data provided is not sufficient to make a
    33  	// a determination. When peek returns EOF that may mean the end of the input or the
    34  	// end of buffered input - recognizers should return the best guess at that time.
    35  	RecognizesData(peek []byte) (ok, unknown bool, err error)
    36  }
    37  
    38  // NewDecoder creates a decoder that will attempt multiple decoders in an order defined
    39  // by:
    40  //
    41  // 1. The decoder implements RecognizingDecoder and identifies the data
    42  // 2. All other decoders, and any decoder that returned true for unknown.
    43  //
    44  // The order passed to the constructor is preserved within those priorities.
    45  func NewDecoder(decoders ...runtime.Decoder) runtime.Decoder {
    46  	return &decoder{
    47  		decoders: decoders,
    48  	}
    49  }
    50  
    51  type decoder struct {
    52  	decoders []runtime.Decoder
    53  }
    54  
    55  var _ RecognizingDecoder = &decoder{}
    56  
    57  func (d *decoder) RecognizesData(data []byte) (bool, bool, error) {
    58  	var (
    59  		lastErr    error
    60  		anyUnknown bool
    61  	)
    62  	for _, r := range d.decoders {
    63  		switch t := r.(type) {
    64  		case RecognizingDecoder:
    65  			ok, unknown, err := t.RecognizesData(data)
    66  			if err != nil {
    67  				lastErr = err
    68  				continue
    69  			}
    70  			anyUnknown = anyUnknown || unknown
    71  			if !ok {
    72  				continue
    73  			}
    74  			return true, false, nil
    75  		}
    76  	}
    77  	return false, anyUnknown, lastErr
    78  }
    79  
    80  func (d *decoder) Decode(data []byte, gvk *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
    81  	var (
    82  		lastErr error
    83  		skipped []runtime.Decoder
    84  	)
    85  
    86  	// try recognizers, record any decoders we need to give a chance later
    87  	for _, r := range d.decoders {
    88  		switch t := r.(type) {
    89  		case RecognizingDecoder:
    90  			ok, unknown, err := t.RecognizesData(data)
    91  			if err != nil {
    92  				lastErr = err
    93  				continue
    94  			}
    95  			if unknown {
    96  				skipped = append(skipped, t)
    97  				continue
    98  			}
    99  			if !ok {
   100  				continue
   101  			}
   102  			return r.Decode(data, gvk, into)
   103  		default:
   104  			skipped = append(skipped, t)
   105  		}
   106  	}
   107  
   108  	// try recognizers that returned unknown or didn't recognize their data
   109  	for _, r := range skipped {
   110  		out, actual, err := r.Decode(data, gvk, into)
   111  		if err != nil {
   112  			// if we got an object back from the decoder, and the
   113  			// error was a strict decoding error (e.g. unknown or
   114  			// duplicate fields), we still consider the recognizer
   115  			// to have understood the object
   116  			if out == nil || !runtime.IsStrictDecodingError(err) {
   117  				lastErr = err
   118  				continue
   119  			}
   120  		}
   121  		return out, actual, err
   122  	}
   123  
   124  	if lastErr == nil {
   125  		lastErr = fmt.Errorf("no serialization format matched the provided data")
   126  	}
   127  	return nil, nil, lastErr
   128  }