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 }