k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/internal/third_party/go-json-experiment/json/fold.go (about)

     1  // Copyright 2020 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package json
     6  
     7  import (
     8  	"unicode"
     9  	"unicode/utf8"
    10  )
    11  
    12  // foldName returns a folded string such that foldName(x) == foldName(y)
    13  // is similar to strings.EqualFold(x, y), but ignores underscore and dashes.
    14  // This allows foldName to match common naming conventions.
    15  func foldName(in []byte) []byte {
    16  	// This is inlinable to take advantage of "function outlining".
    17  	// See https://blog.filippo.io/efficient-go-apis-with-the-inliner/
    18  	var arr [32]byte // large enough for most JSON names
    19  	return appendFoldedName(arr[:0], in)
    20  }
    21  func appendFoldedName(out, in []byte) []byte {
    22  	for i := 0; i < len(in); {
    23  		// Handle single-byte ASCII.
    24  		if c := in[i]; c < utf8.RuneSelf {
    25  			if c != '_' && c != '-' {
    26  				if 'a' <= c && c <= 'z' {
    27  					c -= 'a' - 'A'
    28  				}
    29  				out = append(out, c)
    30  			}
    31  			i++
    32  			continue
    33  		}
    34  		// Handle multi-byte Unicode.
    35  		r, n := utf8.DecodeRune(in[i:])
    36  		out = utf8.AppendRune(out, foldRune(r))
    37  		i += n
    38  	}
    39  	return out
    40  }
    41  
    42  // foldRune is a variation on unicode.SimpleFold that returns the same rune
    43  // for all runes in the same fold set.
    44  //
    45  // Invariant:
    46  //
    47  //	foldRune(x) == foldRune(y) ⇔ strings.EqualFold(string(x), string(y))
    48  func foldRune(r rune) rune {
    49  	for {
    50  		r2 := unicode.SimpleFold(r)
    51  		if r2 <= r {
    52  			return r2 // smallest character in the fold set
    53  		}
    54  		r = r2
    55  	}
    56  }