Remove BPA from Makefile
[icn.git] / cmd / bpa-operator / vendor / k8s.io / apimachinery / pkg / util / intstr / intstr.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 intstr
18
19 import (
20         "encoding/json"
21         "errors"
22         "fmt"
23         "math"
24         "runtime/debug"
25         "strconv"
26         "strings"
27
28         "github.com/google/gofuzz"
29         "k8s.io/klog"
30 )
31
32 // IntOrString is a type that can hold an int32 or a string.  When used in
33 // JSON or YAML marshalling and unmarshalling, it produces or consumes the
34 // inner type.  This allows you to have, for example, a JSON field that can
35 // accept a name or number.
36 // TODO: Rename to Int32OrString
37 //
38 // +protobuf=true
39 // +protobuf.options.(gogoproto.goproto_stringer)=false
40 // +k8s:openapi-gen=true
41 type IntOrString struct {
42         Type   Type   `protobuf:"varint,1,opt,name=type,casttype=Type"`
43         IntVal int32  `protobuf:"varint,2,opt,name=intVal"`
44         StrVal string `protobuf:"bytes,3,opt,name=strVal"`
45 }
46
47 // Type represents the stored type of IntOrString.
48 type Type int
49
50 const (
51         Int    Type = iota // The IntOrString holds an int.
52         String             // The IntOrString holds a string.
53 )
54
55 // FromInt creates an IntOrString object with an int32 value. It is
56 // your responsibility not to call this method with a value greater
57 // than int32.
58 // TODO: convert to (val int32)
59 func FromInt(val int) IntOrString {
60         if val > math.MaxInt32 || val < math.MinInt32 {
61                 klog.Errorf("value: %d overflows int32\n%s\n", val, debug.Stack())
62         }
63         return IntOrString{Type: Int, IntVal: int32(val)}
64 }
65
66 // FromString creates an IntOrString object with a string value.
67 func FromString(val string) IntOrString {
68         return IntOrString{Type: String, StrVal: val}
69 }
70
71 // Parse the given string and try to convert it to an integer before
72 // setting it as a string value.
73 func Parse(val string) IntOrString {
74         i, err := strconv.Atoi(val)
75         if err != nil {
76                 return FromString(val)
77         }
78         return FromInt(i)
79 }
80
81 // UnmarshalJSON implements the json.Unmarshaller interface.
82 func (intstr *IntOrString) UnmarshalJSON(value []byte) error {
83         if value[0] == '"' {
84                 intstr.Type = String
85                 return json.Unmarshal(value, &intstr.StrVal)
86         }
87         intstr.Type = Int
88         return json.Unmarshal(value, &intstr.IntVal)
89 }
90
91 // String returns the string value, or the Itoa of the int value.
92 func (intstr *IntOrString) String() string {
93         if intstr.Type == String {
94                 return intstr.StrVal
95         }
96         return strconv.Itoa(intstr.IntValue())
97 }
98
99 // IntValue returns the IntVal if type Int, or if
100 // it is a String, will attempt a conversion to int.
101 func (intstr *IntOrString) IntValue() int {
102         if intstr.Type == String {
103                 i, _ := strconv.Atoi(intstr.StrVal)
104                 return i
105         }
106         return int(intstr.IntVal)
107 }
108
109 // MarshalJSON implements the json.Marshaller interface.
110 func (intstr IntOrString) MarshalJSON() ([]byte, error) {
111         switch intstr.Type {
112         case Int:
113                 return json.Marshal(intstr.IntVal)
114         case String:
115                 return json.Marshal(intstr.StrVal)
116         default:
117                 return []byte{}, fmt.Errorf("impossible IntOrString.Type")
118         }
119 }
120
121 // OpenAPISchemaType is used by the kube-openapi generator when constructing
122 // the OpenAPI spec of this type.
123 //
124 // See: https://github.com/kubernetes/kube-openapi/tree/master/pkg/generators
125 func (_ IntOrString) OpenAPISchemaType() []string { return []string{"string"} }
126
127 // OpenAPISchemaFormat is used by the kube-openapi generator when constructing
128 // the OpenAPI spec of this type.
129 func (_ IntOrString) OpenAPISchemaFormat() string { return "int-or-string" }
130
131 func (intstr *IntOrString) Fuzz(c fuzz.Continue) {
132         if intstr == nil {
133                 return
134         }
135         if c.RandBool() {
136                 intstr.Type = Int
137                 c.Fuzz(&intstr.IntVal)
138                 intstr.StrVal = ""
139         } else {
140                 intstr.Type = String
141                 intstr.IntVal = 0
142                 c.Fuzz(&intstr.StrVal)
143         }
144 }
145
146 func ValueOrDefault(intOrPercent *IntOrString, defaultValue IntOrString) *IntOrString {
147         if intOrPercent == nil {
148                 return &defaultValue
149         }
150         return intOrPercent
151 }
152
153 func GetValueFromIntOrPercent(intOrPercent *IntOrString, total int, roundUp bool) (int, error) {
154         if intOrPercent == nil {
155                 return 0, errors.New("nil value for IntOrString")
156         }
157         value, isPercent, err := getIntOrPercentValue(intOrPercent)
158         if err != nil {
159                 return 0, fmt.Errorf("invalid value for IntOrString: %v", err)
160         }
161         if isPercent {
162                 if roundUp {
163                         value = int(math.Ceil(float64(value) * (float64(total)) / 100))
164                 } else {
165                         value = int(math.Floor(float64(value) * (float64(total)) / 100))
166                 }
167         }
168         return value, nil
169 }
170
171 func getIntOrPercentValue(intOrStr *IntOrString) (int, bool, error) {
172         switch intOrStr.Type {
173         case Int:
174                 return intOrStr.IntValue(), false, nil
175         case String:
176                 s := strings.Replace(intOrStr.StrVal, "%", "", -1)
177                 v, err := strconv.Atoi(s)
178                 if err != nil {
179                         return 0, false, fmt.Errorf("invalid value %q: %v", intOrStr.StrVal, err)
180                 }
181                 return int(v), true, nil
182         }
183         return 0, false, fmt.Errorf("invalid type: neither int nor percentage")
184 }