Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / k8s.io / apimachinery / pkg / runtime / serializer / recognizer / recognizer.go
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         "bufio"
21         "bytes"
22         "fmt"
23         "io"
24
25         "k8s.io/apimachinery/pkg/runtime"
26         "k8s.io/apimachinery/pkg/runtime/schema"
27 )
28
29 type RecognizingDecoder interface {
30         runtime.Decoder
31         // RecognizesData should return true if the input provided in the provided reader
32         // belongs to this decoder, or an error if the data could not be read or is ambiguous.
33         // Unknown is true if the data could not be determined to match the decoder type.
34         // Decoders should assume that they can read as much of peek as they need (as the caller
35         // provides) and may return unknown if the data provided is not sufficient to make a
36         // a determination. When peek returns EOF that may mean the end of the input or the
37         // end of buffered input - recognizers should return the best guess at that time.
38         RecognizesData(peek io.Reader) (ok, unknown bool, err error)
39 }
40
41 // NewDecoder creates a decoder that will attempt multiple decoders in an order defined
42 // by:
43 //
44 // 1. The decoder implements RecognizingDecoder and identifies the data
45 // 2. All other decoders, and any decoder that returned true for unknown.
46 //
47 // The order passed to the constructor is preserved within those priorities.
48 func NewDecoder(decoders ...runtime.Decoder) runtime.Decoder {
49         return &decoder{
50                 decoders: decoders,
51         }
52 }
53
54 type decoder struct {
55         decoders []runtime.Decoder
56 }
57
58 var _ RecognizingDecoder = &decoder{}
59
60 func (d *decoder) RecognizesData(peek io.Reader) (bool, bool, error) {
61         var (
62                 lastErr    error
63                 anyUnknown bool
64         )
65         data, _ := bufio.NewReaderSize(peek, 1024).Peek(1024)
66         for _, r := range d.decoders {
67                 switch t := r.(type) {
68                 case RecognizingDecoder:
69                         ok, unknown, err := t.RecognizesData(bytes.NewBuffer(data))
70                         if err != nil {
71                                 lastErr = err
72                                 continue
73                         }
74                         anyUnknown = anyUnknown || unknown
75                         if !ok {
76                                 continue
77                         }
78                         return true, false, nil
79                 }
80         }
81         return false, anyUnknown, lastErr
82 }
83
84 func (d *decoder) Decode(data []byte, gvk *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
85         var (
86                 lastErr error
87                 skipped []runtime.Decoder
88         )
89
90         // try recognizers, record any decoders we need to give a chance later
91         for _, r := range d.decoders {
92                 switch t := r.(type) {
93                 case RecognizingDecoder:
94                         buf := bytes.NewBuffer(data)
95                         ok, unknown, err := t.RecognizesData(buf)
96                         if err != nil {
97                                 lastErr = err
98                                 continue
99                         }
100                         if unknown {
101                                 skipped = append(skipped, t)
102                                 continue
103                         }
104                         if !ok {
105                                 continue
106                         }
107                         return r.Decode(data, gvk, into)
108                 default:
109                         skipped = append(skipped, t)
110                 }
111         }
112
113         // try recognizers that returned unknown or didn't recognize their data
114         for _, r := range skipped {
115                 out, actual, err := r.Decode(data, gvk, into)
116                 if err != nil {
117                         lastErr = err
118                         continue
119                 }
120                 return out, actual, nil
121         }
122
123         if lastErr == nil {
124                 lastErr = fmt.Errorf("no serialization format matched the provided data")
125         }
126         return nil, nil, lastErr
127 }