vitess.io/vitess@v0.16.2/go/flagutil/optional.go (about) 1 /* 2 Copyright 2021 The Vitess 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 flagutil 18 19 import ( 20 "errors" 21 "strconv" 22 23 "github.com/spf13/pflag" 24 ) 25 26 // OptionalFlag augements the pflag.Value interface with a method to determine 27 // if a flag was set explicitly on the comand-line. 28 // 29 // Though not part of the interface, because the return type would be different 30 // for each implementation, by convention, each implementation should define a 31 // Get() method to access the underlying value. 32 // 33 // TODO (ajm188) - replace this interface with a generic type. 34 // c.f. https://github.com/vitessio/vitess/issues/11154. 35 type OptionalFlag interface { 36 pflag.Value 37 IsSet() bool 38 } 39 40 var ( 41 _ OptionalFlag = (*OptionalFloat64)(nil) 42 _ OptionalFlag = (*OptionalString)(nil) 43 ) 44 45 // OptionalFloat64 implements OptionalFlag for float64 values. 46 type OptionalFloat64 struct { 47 val float64 48 set bool 49 } 50 51 // NewOptionalFloat64 returns an OptionalFloat64 with the specified value as its 52 // starting value. 53 func NewOptionalFloat64(val float64) *OptionalFloat64 { 54 return &OptionalFloat64{ 55 val: val, 56 set: false, 57 } 58 } 59 60 // Set is part of the pflag.Value interface. 61 func (f *OptionalFloat64) Set(arg string) error { 62 v, err := strconv.ParseFloat(arg, 64) 63 if err != nil { 64 return numError(err) 65 } 66 67 f.val = v 68 f.set = true 69 70 return nil 71 } 72 73 // String is part of the pflag.Value interface. 74 func (f *OptionalFloat64) String() string { 75 return strconv.FormatFloat(f.val, 'g', -1, 64) 76 } 77 78 // Type is part of the pflag.Value interface. 79 func (f *OptionalFloat64) Type() string { 80 return "float64" 81 } 82 83 // Get returns the underlying float64 value of this flag. If the flag was not 84 // explicitly set, this will be the initial value passed to the constructor. 85 func (f *OptionalFloat64) Get() float64 { 86 return f.val 87 } 88 89 // IsSet is part of the OptionalFlag interface. 90 func (f *OptionalFloat64) IsSet() bool { 91 return f.set 92 } 93 94 // OptionalString implements OptionalFlag for string values. 95 type OptionalString struct { 96 val string 97 set bool 98 } 99 100 // NewOptionalString returns an OptionalString with the specified value as its 101 // starting value. 102 func NewOptionalString(val string) *OptionalString { 103 return &OptionalString{ 104 val: val, 105 set: false, 106 } 107 } 108 109 // Set is part of the pflag.Value interface. 110 func (f *OptionalString) Set(arg string) error { 111 f.val = arg 112 f.set = true 113 return nil 114 } 115 116 // String is part of the pflag.Value interface. 117 func (f *OptionalString) String() string { 118 return f.val 119 } 120 121 // Type is part of the pflag.Value interface. 122 func (f *OptionalString) Type() string { 123 return "string" 124 } 125 126 // Get returns the underlying string value of this flag. If the flag was not 127 // explicitly set, this will be the initial value passed to the constructor. 128 func (f *OptionalString) Get() string { 129 return f.val 130 } 131 132 // IsSet is part of the OptionalFlag interface. 133 func (f *OptionalString) IsSet() bool { 134 return f.set 135 } 136 137 // lifted directly from package flag to make the behavior of numeric parsing 138 // consistent with the standard library for our custom optional types. 139 var ( 140 errParse = errors.New("parse error") 141 errRange = errors.New("value out of range") 142 ) 143 144 // lifted directly from package flag to make the behavior of numeric parsing 145 // consistent with the standard library for our custom optional types. 146 func numError(err error) error { 147 ne, ok := err.(*strconv.NumError) 148 if !ok { 149 return err 150 } 151 152 switch ne.Err { 153 case strconv.ErrSyntax: 154 return errParse 155 case strconv.ErrRange: 156 return errRange 157 default: 158 return err 159 } 160 }