123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- /*
- Copyright 2014 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package intstr
- import (
- "encoding/json"
- "fmt"
- "math"
- "strconv"
- "strings"
- "github.com/google/gofuzz"
- )
- // IntOrString is a type that can hold an int32 or a string. When used in
- // JSON or YAML marshalling and unmarshalling, it produces or consumes the
- // inner type. This allows you to have, for example, a JSON field that can
- // accept a name or number.
- // TODO: Rename to Int32OrString
- //
- // +protobuf=true
- // +protobuf.options.(gogoproto.goproto_stringer)=false
- type IntOrString struct {
- Type Type `protobuf:"varint,1,opt,name=type,casttype=Type"`
- IntVal int32 `protobuf:"varint,2,opt,name=intVal"`
- StrVal string `protobuf:"bytes,3,opt,name=strVal"`
- }
- // Type represents the stored type of IntOrString.
- type Type int
- const (
- Int Type = iota // The IntOrString holds an int.
- String // The IntOrString holds a string.
- )
- // FromInt creates an IntOrString object with an int32 value. It is
- // your responsibility not to call this method with a value greater
- // than int32.
- // TODO: convert to (val int32)
- func FromInt(val int) IntOrString {
- return IntOrString{Type: Int, IntVal: int32(val)}
- }
- // FromString creates an IntOrString object with a string value.
- func FromString(val string) IntOrString {
- return IntOrString{Type: String, StrVal: val}
- }
- // UnmarshalJSON implements the json.Unmarshaller interface.
- func (intstr *IntOrString) UnmarshalJSON(value []byte) error {
- if value[0] == '"' {
- intstr.Type = String
- return json.Unmarshal(value, &intstr.StrVal)
- }
- intstr.Type = Int
- return json.Unmarshal(value, &intstr.IntVal)
- }
- // String returns the string value, or the Itoa of the int value.
- func (intstr *IntOrString) String() string {
- if intstr.Type == String {
- return intstr.StrVal
- }
- return strconv.Itoa(intstr.IntValue())
- }
- // IntValue returns the IntVal if type Int, or if
- // it is a String, will attempt a conversion to int.
- func (intstr *IntOrString) IntValue() int {
- if intstr.Type == String {
- i, _ := strconv.Atoi(intstr.StrVal)
- return i
- }
- return int(intstr.IntVal)
- }
- // MarshalJSON implements the json.Marshaller interface.
- func (intstr IntOrString) MarshalJSON() ([]byte, error) {
- switch intstr.Type {
- case Int:
- return json.Marshal(intstr.IntVal)
- case String:
- return json.Marshal(intstr.StrVal)
- default:
- return []byte{}, fmt.Errorf("impossible IntOrString.Type")
- }
- }
- func (intstr *IntOrString) Fuzz(c fuzz.Continue) {
- if intstr == nil {
- return
- }
- if c.RandBool() {
- intstr.Type = Int
- c.Fuzz(&intstr.IntVal)
- intstr.StrVal = ""
- } else {
- intstr.Type = String
- intstr.IntVal = 0
- c.Fuzz(&intstr.StrVal)
- }
- }
- func GetValueFromIntOrPercent(intOrPercent *IntOrString, total int, roundUp bool) (int, error) {
- value, isPercent, err := getIntOrPercentValue(intOrPercent)
- if err != nil {
- return 0, fmt.Errorf("invalid value for IntOrString: %v", err)
- }
- if isPercent {
- if roundUp {
- value = int(math.Ceil(float64(value) * (float64(total)) / 100))
- } else {
- value = int(math.Floor(float64(value) * (float64(total)) / 100))
- }
- }
- return value, nil
- }
- func getIntOrPercentValue(intOrStr *IntOrString) (int, bool, error) {
- switch intOrStr.Type {
- case Int:
- return intOrStr.IntValue(), false, nil
- case String:
- s := strings.Replace(intOrStr.StrVal, "%", "", -1)
- v, err := strconv.Atoi(s)
- if err != nil {
- return 0, false, fmt.Errorf("invalid value %q: %v", intOrStr.StrVal, err)
- }
- return int(v), true, nil
- }
- return 0, false, fmt.Errorf("invalid type: neither int nor percentage")
- }
|