This file is indexed.

/usr/share/gocode/src/github.com/goji/param/struct.go is in golang-github-goji-param-dev 0.0~git20160927.d7f49fd-4.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package param

import (
	"reflect"
	"strings"
	"sync"
)

// We decode a lot of structs (since it's the top-level thing this library
// decodes) and it takes a fair bit of work to reflect upon the struct to figure
// out what we want to do. Instead of doing this on every invocation, we cache
// metadata about each struct the first time we see it. The upshot is that we
// save some work every time. The downside is we are forced to briefly acquire
// a lock to access the cache in a thread-safe way. If this ever becomes a
// bottleneck, both the lock and the cache can be sharded or something.
type structCache map[string]cacheLine
type cacheLine struct {
	offset int
	parse  func(string, string, []string, reflect.Value)
}

var cacheLock sync.RWMutex
var cache = make(map[reflect.Type]structCache)

func cacheStruct(t reflect.Type) structCache {
	cacheLock.RLock()
	sc, ok := cache[t]
	cacheLock.RUnlock()

	if ok {
		return sc
	}

	// It's okay if two people build struct caches simultaneously
	sc = make(structCache)
	for i := 0; i < t.NumField(); i++ {
		sf := t.Field(i)
		// Only unexported fields have a PkgPath; we want to only cache
		// exported fields.
		if sf.PkgPath != "" && !sf.Anonymous {
			continue
		}
		name := extractName(sf)
		if name != "-" {
			sc[name] = cacheLine{i, extractHandler(t, sf)}
		}
	}

	cacheLock.Lock()
	cache[t] = sc
	cacheLock.Unlock()

	return sc
}

// Extract the name of the given struct field, looking at struct tags as
// appropriate.
func extractName(sf reflect.StructField) string {
	name := sf.Tag.Get("param")
	if name == "" {
		name = sf.Tag.Get("json")
		idx := strings.IndexRune(name, ',')
		if idx >= 0 {
			name = name[:idx]
		}
	}
	if name == "" {
		name = sf.Name
	}

	return name
}

func extractHandler(s reflect.Type, sf reflect.StructField) func(string, string, []string, reflect.Value) {
	if reflect.PtrTo(sf.Type).Implements(textUnmarshalerType) {
		return parseTextUnmarshaler
	}

	switch sf.Type.Kind() {
	case reflect.Bool:
		return parseBool
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return parseInt
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return parseUint
	case reflect.Float32, reflect.Float64:
		return parseFloat
	case reflect.Map:
		return parseMap
	case reflect.Ptr:
		return parsePtr
	case reflect.Slice:
		return parseSlice
	case reflect.String:
		return parseString
	case reflect.Struct:
		return parseStruct

	default:
		pebkac("struct %v has illegal field %q (type %v, kind %v).",
			s, sf.Name, sf.Type, sf.Type.Kind())
		return nil
	}
}

// We have to parse two types of structs: ones at the top level, whose keys
// don't have square brackets around them, and nested structs, which do.
func parseStructField(cache structCache, key, sk, keytail string, values []string, target reflect.Value) {
	l, ok := cache[sk]
	if !ok {
		panic(KeyError{
			FullKey: key,
			Key:     kpath(key, keytail),
			Type:    target.Type(),
			Field:   sk,
		})
	}
	f := target.Field(l.offset)

	l.parse(key, keytail, values, f)
}