k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/validation/strfmt/format.go (about) 1 // Copyright 2015 go-swagger maintainers 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package strfmt 16 17 import ( 18 "encoding" 19 "reflect" 20 "strings" 21 "sync" 22 23 "k8s.io/kube-openapi/pkg/validation/errors" 24 ) 25 26 // Default is the default formats registry 27 var Default = NewSeededFormats(nil, nil) 28 29 // Validator represents a validator for a string format. 30 type Validator func(string) bool 31 32 // Format represents a string format. 33 // 34 // All implementations of Format provide a string representation and text 35 // marshaling/unmarshaling interface to be used by encoders (e.g. encoding/json). 36 type Format interface { 37 String() string 38 encoding.TextMarshaler 39 encoding.TextUnmarshaler 40 } 41 42 // Registry is a registry of string formats, with a validation method. 43 type Registry interface { 44 Add(string, Format, Validator) bool 45 DelByName(string) bool 46 GetType(string) (reflect.Type, bool) 47 ContainsName(string) bool 48 Validates(string, string) bool 49 Parse(string, string) (interface{}, error) 50 } 51 52 type knownFormat struct { 53 Name string 54 OrigName string 55 Type reflect.Type 56 Validator Validator 57 } 58 59 // NameNormalizer is a function that normalizes a format name. 60 type NameNormalizer func(string) string 61 62 // DefaultNameNormalizer removes all dashes 63 func DefaultNameNormalizer(name string) string { 64 return strings.Replace(name, "-", "", -1) 65 } 66 67 type defaultFormats struct { 68 sync.Mutex 69 data []knownFormat 70 normalizeName NameNormalizer 71 } 72 73 // NewFormats creates a new formats registry seeded with the values from the default 74 func NewFormats() Registry { 75 return NewSeededFormats(Default.(*defaultFormats).data, nil) 76 } 77 78 // NewSeededFormats creates a new formats registry 79 func NewSeededFormats(seeds []knownFormat, normalizer NameNormalizer) Registry { 80 if normalizer == nil { 81 normalizer = DefaultNameNormalizer 82 } 83 // copy here, don't modify original 84 d := append([]knownFormat(nil), seeds...) 85 return &defaultFormats{ 86 data: d, 87 normalizeName: normalizer, 88 } 89 } 90 91 // Add adds a new format, return true if this was a new item instead of a replacement 92 func (f *defaultFormats) Add(name string, strfmt Format, validator Validator) bool { 93 f.Lock() 94 defer f.Unlock() 95 96 nme := f.normalizeName(name) 97 98 tpe := reflect.TypeOf(strfmt) 99 if tpe.Kind() == reflect.Ptr { 100 tpe = tpe.Elem() 101 } 102 103 for i := range f.data { 104 v := &f.data[i] 105 if v.Name == nme { 106 v.Type = tpe 107 v.Validator = validator 108 return false 109 } 110 } 111 112 // turns out it's new after all 113 f.data = append(f.data, knownFormat{Name: nme, OrigName: name, Type: tpe, Validator: validator}) 114 return true 115 } 116 117 // GetType gets the type for the specified name 118 func (f *defaultFormats) GetType(name string) (reflect.Type, bool) { 119 f.Lock() 120 defer f.Unlock() 121 nme := f.normalizeName(name) 122 for _, v := range f.data { 123 if v.Name == nme { 124 return v.Type, true 125 } 126 } 127 return nil, false 128 } 129 130 // DelByName removes the format by the specified name, returns true when an item was actually removed 131 func (f *defaultFormats) DelByName(name string) bool { 132 f.Lock() 133 defer f.Unlock() 134 135 nme := f.normalizeName(name) 136 137 for i, v := range f.data { 138 if v.Name == nme { 139 f.data[i] = knownFormat{} // release 140 f.data = append(f.data[:i], f.data[i+1:]...) 141 return true 142 } 143 } 144 return false 145 } 146 147 // DelByFormat removes the specified format, returns true when an item was actually removed 148 func (f *defaultFormats) DelByFormat(strfmt Format) bool { 149 f.Lock() 150 defer f.Unlock() 151 152 tpe := reflect.TypeOf(strfmt) 153 if tpe.Kind() == reflect.Ptr { 154 tpe = tpe.Elem() 155 } 156 157 for i, v := range f.data { 158 if v.Type == tpe { 159 f.data[i] = knownFormat{} // release 160 f.data = append(f.data[:i], f.data[i+1:]...) 161 return true 162 } 163 } 164 return false 165 } 166 167 // ContainsName returns true if this registry contains the specified name 168 func (f *defaultFormats) ContainsName(name string) bool { 169 f.Lock() 170 defer f.Unlock() 171 nme := f.normalizeName(name) 172 for _, v := range f.data { 173 if v.Name == nme { 174 return true 175 } 176 } 177 return false 178 } 179 180 // ContainsFormat returns true if this registry contains the specified format 181 func (f *defaultFormats) ContainsFormat(strfmt Format) bool { 182 f.Lock() 183 defer f.Unlock() 184 tpe := reflect.TypeOf(strfmt) 185 if tpe.Kind() == reflect.Ptr { 186 tpe = tpe.Elem() 187 } 188 189 for _, v := range f.data { 190 if v.Type == tpe { 191 return true 192 } 193 } 194 return false 195 } 196 197 // Validates passed data against format. 198 // 199 // Note that the format name is automatically normalized, e.g. one may 200 // use "date-time" to use the "datetime" format validator. 201 func (f *defaultFormats) Validates(name, data string) bool { 202 f.Lock() 203 defer f.Unlock() 204 nme := f.normalizeName(name) 205 for _, v := range f.data { 206 if v.Name == nme { 207 return v.Validator(data) 208 } 209 } 210 return false 211 } 212 213 // Parse a string into the appropriate format representation type. 214 // 215 // E.g. parsing a string a "date" will return a Date type. 216 func (f *defaultFormats) Parse(name, data string) (interface{}, error) { 217 f.Lock() 218 defer f.Unlock() 219 nme := f.normalizeName(name) 220 for _, v := range f.data { 221 if v.Name == nme { 222 nw := reflect.New(v.Type).Interface() 223 if dec, ok := nw.(encoding.TextUnmarshaler); ok { 224 if err := dec.UnmarshalText([]byte(data)); err != nil { 225 return nil, err 226 } 227 return nw, nil 228 } 229 return nil, errors.InvalidTypeName(name) 230 } 231 } 232 return nil, errors.InvalidTypeName(name) 233 }