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  }