mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 13:50:01 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			149 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			149 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| 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
 | |
| //
 | |
| // +gencopy=true
 | |
| // +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")
 | |
| }
 |