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