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  }