github.com/jhump/protocompile@v0.0.0-20221021153901-4f6f732835e8/internal/util.go (about)

     1  package internal
     2  
     3  import (
     4  	"bytes"
     5  	"unicode"
     6  	"unicode/utf8"
     7  )
     8  
     9  // JsonName returns the default JSON name for a field with the given name.
    10  func JsonName(name string) string {
    11  	var js []rune
    12  	nextUpper := false
    13  	for i, r := range name {
    14  		if r == '_' {
    15  			nextUpper = true
    16  			continue
    17  		}
    18  		if i == 0 {
    19  			js = append(js, r)
    20  		} else if nextUpper {
    21  			nextUpper = false
    22  			js = append(js, unicode.ToUpper(r))
    23  		} else {
    24  			js = append(js, r)
    25  		}
    26  	}
    27  	return string(js)
    28  }
    29  
    30  // InitCap returns the given field name, but with the first letter capitalized.
    31  func InitCap(name string) string {
    32  	r, sz := utf8.DecodeRuneInString(name)
    33  	return string(unicode.ToUpper(r)) + name[sz:]
    34  }
    35  
    36  // CreatePrefixList returns a list of package prefixes to search when resolving
    37  // a symbol name. If the given package is blank, it returns only the empty
    38  // string. If the given package contains only one token, e.g. "foo", it returns
    39  // that token and the empty string, e.g. ["foo", ""]. Otherwise, it returns
    40  // successively shorter prefixes of the package and then the empty string. For
    41  // example, for a package named "foo.bar.baz" it will return the following list:
    42  //   ["foo.bar.baz", "foo.bar", "foo", ""]
    43  func CreatePrefixList(pkg string) []string {
    44  	if pkg == "" {
    45  		return []string{""}
    46  	}
    47  
    48  	numDots := 0
    49  	// one pass to pre-allocate the returned slice
    50  	for i := 0; i < len(pkg); i++ {
    51  		if pkg[i] == '.' {
    52  			numDots++
    53  		}
    54  	}
    55  	if numDots == 0 {
    56  		return []string{pkg, ""}
    57  	}
    58  
    59  	prefixes := make([]string, numDots+2)
    60  	// second pass to fill in returned slice
    61  	for i := 0; i < len(pkg); i++ {
    62  		if pkg[i] == '.' {
    63  			prefixes[numDots] = pkg[:i]
    64  			numDots--
    65  		}
    66  	}
    67  	prefixes[0] = pkg
    68  
    69  	return prefixes
    70  }
    71  
    72  func WriteEscapedBytes(buf *bytes.Buffer, b []byte) {
    73  	for _, c := range b {
    74  		switch c {
    75  		case '\n':
    76  			buf.WriteString("\\n")
    77  		case '\r':
    78  			buf.WriteString("\\r")
    79  		case '\t':
    80  			buf.WriteString("\\t")
    81  		case '"':
    82  			buf.WriteString("\\\"")
    83  		case '\'':
    84  			buf.WriteString("\\'")
    85  		case '\\':
    86  			buf.WriteString("\\\\")
    87  		default:
    88  			if c >= 0x20 && c <= 0x7f && c != '"' && c != '\\' {
    89  				// simple printable characters
    90  				buf.WriteByte(c)
    91  			} else {
    92  				// use octal escape for all other values
    93  				buf.WriteRune('\\')
    94  				buf.WriteByte('0' + ((c >> 6) & 0x7))
    95  				buf.WriteByte('0' + ((c >> 3) & 0x7))
    96  				buf.WriteByte('0' + (c & 0x7))
    97  			}
    98  		}
    99  	}
   100  }