github.com/aclisp/heapster@v0.19.2-0.20160613100040-51756f899a96/Godeps/_workspace/src/k8s.io/kubernetes/pkg/util/intstr/intstr.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors All rights reserved. 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 "fmt" 22 "math" 23 "strconv" 24 "strings" 25 26 "github.com/google/gofuzz" 27 ) 28 29 // IntOrString is a type that can hold an int32 or a string. When used in 30 // JSON or YAML marshalling and unmarshalling, it produces or consumes the 31 // inner type. This allows you to have, for example, a JSON field that can 32 // accept a name or number. 33 // TODO: Rename to Int32OrString 34 // 35 // +protobuf=true 36 // +protobuf.options.(gogoproto.goproto_stringer)=false 37 type IntOrString struct { 38 Type Type `protobuf:"varint,1,opt,name=type,casttype=Type"` 39 IntVal int32 `protobuf:"varint,2,opt,name=intVal"` 40 StrVal string `protobuf:"bytes,3,opt,name=strVal"` 41 } 42 43 // Type represents the stored type of IntOrString. 44 type Type int 45 46 const ( 47 Int Type = iota // The IntOrString holds an int. 48 String // The IntOrString holds a string. 49 ) 50 51 // FromInt creates an IntOrString object with an int32 value. It is 52 // your responsibility not to call this method with a value greater 53 // than int32. 54 // TODO: convert to (val int32) 55 func FromInt(val int) IntOrString { 56 return IntOrString{Type: Int, IntVal: int32(val)} 57 } 58 59 // FromString creates an IntOrString object with a string value. 60 func FromString(val string) IntOrString { 61 return IntOrString{Type: String, StrVal: val} 62 } 63 64 // UnmarshalJSON implements the json.Unmarshaller interface. 65 func (intstr *IntOrString) UnmarshalJSON(value []byte) error { 66 if value[0] == '"' { 67 intstr.Type = String 68 return json.Unmarshal(value, &intstr.StrVal) 69 } 70 intstr.Type = Int 71 return json.Unmarshal(value, &intstr.IntVal) 72 } 73 74 // String returns the string value, or the Itoa of the int value. 75 func (intstr *IntOrString) String() string { 76 if intstr.Type == String { 77 return intstr.StrVal 78 } 79 return strconv.Itoa(intstr.IntValue()) 80 } 81 82 // IntValue returns the IntVal if type Int, or if 83 // it is a String, will attempt a conversion to int. 84 func (intstr *IntOrString) IntValue() int { 85 if intstr.Type == String { 86 i, _ := strconv.Atoi(intstr.StrVal) 87 return i 88 } 89 return int(intstr.IntVal) 90 } 91 92 // MarshalJSON implements the json.Marshaller interface. 93 func (intstr IntOrString) MarshalJSON() ([]byte, error) { 94 switch intstr.Type { 95 case Int: 96 return json.Marshal(intstr.IntVal) 97 case String: 98 return json.Marshal(intstr.StrVal) 99 default: 100 return []byte{}, fmt.Errorf("impossible IntOrString.Type") 101 } 102 } 103 104 func (intstr *IntOrString) Fuzz(c fuzz.Continue) { 105 if intstr == nil { 106 return 107 } 108 if c.RandBool() { 109 intstr.Type = Int 110 c.Fuzz(&intstr.IntVal) 111 intstr.StrVal = "" 112 } else { 113 intstr.Type = String 114 intstr.IntVal = 0 115 c.Fuzz(&intstr.StrVal) 116 } 117 } 118 119 func GetValueFromIntOrPercent(intOrPercent *IntOrString, total int, roundUp bool) (int, error) { 120 value, isPercent, err := getIntOrPercentValue(intOrPercent) 121 if err != nil { 122 return 0, fmt.Errorf("invalid value for IntOrString: %v", err) 123 } 124 if isPercent { 125 if roundUp { 126 value = int(math.Ceil(float64(value) * (float64(total)) / 100)) 127 } else { 128 value = int(math.Floor(float64(value) * (float64(total)) / 100)) 129 } 130 } 131 return value, nil 132 } 133 134 func getIntOrPercentValue(intOrStr *IntOrString) (int, bool, error) { 135 switch intOrStr.Type { 136 case Int: 137 return intOrStr.IntValue(), false, nil 138 case String: 139 s := strings.Replace(intOrStr.StrVal, "%", "", -1) 140 v, err := strconv.Atoi(s) 141 if err != nil { 142 return 0, false, fmt.Errorf("invalid value %q: %v", intOrStr.StrVal, err) 143 } 144 return int(v), true, nil 145 } 146 return 0, false, fmt.Errorf("invalid value: neither int nor percentage") 147 }