github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/internal/output.go (about)

     1  package internal
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"go/format"
     7  	"go/scanner"
     8  	"io"
     9  	"reflect"
    10  	"strings"
    11  	"unicode"
    12  )
    13  
    14  // Identifier turns a C style type or field name into an exportable Go equivalent.
    15  func Identifier(str string) string {
    16  	prev := rune(-1)
    17  	return strings.Map(func(r rune) rune {
    18  		// See https://golang.org/ref/spec#Identifiers
    19  		switch {
    20  		case unicode.IsLetter(r):
    21  			if prev == -1 {
    22  				r = unicode.ToUpper(r)
    23  			}
    24  
    25  		case r == '_':
    26  			switch {
    27  			// The previous rune was deleted, or we are at the
    28  			// beginning of the string.
    29  			case prev == -1:
    30  				fallthrough
    31  
    32  			// The previous rune is a lower case letter or a digit.
    33  			case unicode.IsDigit(prev) || (unicode.IsLetter(prev) && unicode.IsLower(prev)):
    34  				// delete the current rune, and force the
    35  				// next character to be uppercased.
    36  				r = -1
    37  			}
    38  
    39  		case unicode.IsDigit(r):
    40  
    41  		default:
    42  			// Delete the current rune. prev is unchanged.
    43  			return -1
    44  		}
    45  
    46  		prev = r
    47  		return r
    48  	}, str)
    49  }
    50  
    51  // WriteFormatted outputs a formatted src into out.
    52  //
    53  // If formatting fails it returns an informative error message.
    54  func WriteFormatted(src []byte, out io.Writer) error {
    55  	formatted, err := format.Source(src)
    56  	if err == nil {
    57  		_, err = out.Write(formatted)
    58  		return err
    59  	}
    60  
    61  	var el scanner.ErrorList
    62  	if !errors.As(err, &el) {
    63  		return err
    64  	}
    65  
    66  	var nel scanner.ErrorList
    67  	for _, err := range el {
    68  		if !err.Pos.IsValid() {
    69  			nel = append(nel, err)
    70  			continue
    71  		}
    72  
    73  		buf := src[err.Pos.Offset:]
    74  		nl := bytes.IndexRune(buf, '\n')
    75  		if nl == -1 {
    76  			nel = append(nel, err)
    77  			continue
    78  		}
    79  
    80  		err.Msg += ": " + string(buf[:nl])
    81  		nel = append(nel, err)
    82  	}
    83  
    84  	return nel
    85  }
    86  
    87  // GoTypeName is like %T, but elides the package name.
    88  //
    89  // Pointers to a type are peeled off.
    90  func GoTypeName(t any) string {
    91  	rT := reflect.TypeOf(t)
    92  	for rT.Kind() == reflect.Pointer {
    93  		rT = rT.Elem()
    94  	}
    95  	// Doesn't return the correct Name for generic types due to https://github.com/golang/go/issues/55924
    96  	return rT.Name()
    97  }