#136: Start working on database persistence

This commit is contained in:
TwinProduction
2021-07-12 00:56:30 -04:00
committed by Chris
parent e6335da94f
commit bd1eb7c61b
657 changed files with 2190821 additions and 82 deletions

12
vendor/modernc.org/strutil/AUTHORS generated vendored Normal file
View File

@ -0,0 +1,12 @@
# This file lists authors for copyright purposes. This file is distinct from
# the CONTRIBUTORS files. See the latter for an explanation.
#
# Names should be added to this file as:
# Name or Organization <email address>
#
# The email address is not required for organizations.
#
# Please keep the list sorted.
CZ.NIC z.s.p.o. <kontakt@nic.cz>
Jan Mercl <0xjnml@gmail.com>

9
vendor/modernc.org/strutil/CONTRIBUTORS generated vendored Normal file
View File

@ -0,0 +1,9 @@
# This file lists people who contributed code to this repository. The AUTHORS
# file lists the copyright holders; this file lists people.
#
# Names should be added to this file like so:
# Name <email address>
#
# Please keep the list sorted.
Jan Mercl <0xjnml@gmail.com>

27
vendor/modernc.org/strutil/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2014 The strutil Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the names of the authors nor the names of the
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

59
vendor/modernc.org/strutil/Makefile generated vendored Normal file
View File

@ -0,0 +1,59 @@
# Copyright (c) 2014 The sortutil Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
.PHONY: all clean cover cpu editor internalError later mem nuke todo edit
grep=--include=*.go --include=*.l --include=*.y --include=*.yy
ngrep='TODOOK\|parser\.go\|scanner\.go\|.*_string\.go'
all: editor
go vet 2>&1 | grep -v $(ngrep) || true
golint 2>&1 | grep -v $(ngrep) || true
make todo
unused . || true
misspell *.go
gosimple || true
maligned || true
unconvert -apply
clean:
go clean
rm -f *~ *.test *.out
cover:
t=$(shell tempfile) ; go test -coverprofile $$t && go tool cover -html $$t && unlink $$t
cpu: clean
go test -run @ -bench . -cpuprofile cpu.out
go tool pprof -lines *.test cpu.out
edit:
@ 1>/dev/null 2>/dev/null gvim -p Makefile *.go
editor:
unconvert -apply || true
gofmt -l -s -w *.go
go test -i
go test 2>&1 | tee log
go install
internalError:
egrep -ho '"internal error.*"' *.go | sort | cat -n
later:
@grep -n $(grep) LATER * || true
@grep -n $(grep) MAYBE * || true
mem: clean
go test -run @ -bench . -memprofile mem.out -memprofilerate 1 -timeout 24h
go tool pprof -lines -web -alloc_space *.test mem.out
nuke: clean
go clean -i
todo:
@grep -nr $(grep) ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* * | grep -v $(ngrep) || true
@grep -nr $(grep) TODO * | grep -v $(ngrep) || true
@grep -nr $(grep) BUG * | grep -v $(ngrep) || true
@grep -nr $(grep) [^[:alpha:]]println * | grep -v $(ngrep) || true

8
vendor/modernc.org/strutil/README generated vendored Normal file
View File

@ -0,0 +1,8 @@
modernc.orgall-able mirror of modified code already published at:
http://git.nic.cz/redmine/projects/gostrutil/repository
Online godoc documentation for this package (should be) available at:
http://gopkgdoc.appspot.com/pkg/modernc.org/strutil
Installation:
$ go get modernc.org/strutil

5
vendor/modernc.org/strutil/go.mod generated vendored Normal file
View File

@ -0,0 +1,5 @@
module modernc.org/strutil
go 1.15
require modernc.org/mathutil v1.2.2

4
vendor/modernc.org/strutil/go.sum generated vendored Normal file
View File

@ -0,0 +1,4 @@
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
modernc.org/mathutil v1.2.2 h1:+yFk8hBprV+4c0U9GjFtL+dV3N8hOJ8JCituQcMShFY=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=

733
vendor/modernc.org/strutil/strutil.go generated vendored Normal file
View File

@ -0,0 +1,733 @@
// Copyright (c) 2014 The sortutil Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package strutil collects utils supplemental to the standard strings package.
package strutil // import "modernc.org/strutil"
import (
"bytes"
"encoding/base32"
"encoding/base64"
"fmt"
"io"
"os"
"path/filepath"
"reflect"
"runtime"
"sort"
"strconv"
"strings"
"sync"
)
// Base32ExtDecode decodes base32 extended (RFC 4648) text to binary data.
func Base32ExtDecode(text []byte) (data []byte, err error) {
n := base32.HexEncoding.DecodedLen(len(text))
data = make([]byte, n)
decoder := base32.NewDecoder(base32.HexEncoding, bytes.NewBuffer(text))
if n, err = decoder.Read(data); err != nil {
n = 0
}
data = data[:n]
return
}
// Base32ExtEncode encodes binary data to base32 extended (RFC 4648) encoded text.
func Base32ExtEncode(data []byte) (text []byte) {
n := base32.HexEncoding.EncodedLen(len(data))
buf := bytes.NewBuffer(make([]byte, 0, n))
encoder := base32.NewEncoder(base32.HexEncoding, buf)
encoder.Write(data)
encoder.Close()
if buf.Len() != n {
panic("internal error")
}
return buf.Bytes()
}
// Base64Decode decodes base64 text to binary data.
func Base64Decode(text []byte) (data []byte, err error) {
n := base64.StdEncoding.DecodedLen(len(text))
data = make([]byte, n)
decoder := base64.NewDecoder(base64.StdEncoding, bytes.NewBuffer(text))
if n, err = decoder.Read(data); err != nil {
n = 0
}
data = data[:n]
return
}
// Base64Encode encodes binary data to base64 encoded text.
func Base64Encode(data []byte) (text []byte) {
n := base64.StdEncoding.EncodedLen(len(data))
buf := bytes.NewBuffer(make([]byte, 0, n))
encoder := base64.NewEncoder(base64.StdEncoding, buf)
encoder.Write(data)
encoder.Close()
if buf.Len() != n {
panic("internal error")
}
return buf.Bytes()
}
// Formatter is an io.Writer extended by a fmt.Printf like function Format
type Formatter interface {
io.Writer
Format(format string, args ...interface{}) (n int, errno error)
}
type indentFormatter struct {
io.Writer
indent []byte
indentLevel int
state int
}
const (
st0 = iota
stBOL
stPERC
stBOLPERC
)
// IndentFormatter returns a new Formatter which interprets %i and %u in the
// Format() format string as indent and undent commands. The commands can
// nest. The Formatter writes to io.Writer 'w' and inserts one 'indent'
// string per current indent level value.
// Behaviour of commands reaching negative indent levels is undefined.
// IndentFormatter(os.Stdout, "\t").Format("abc%d%%e%i\nx\ny\n%uz\n", 3)
// output:
// abc3%e
// x
// y
// z
// The Go quoted string literal form of the above is:
// "abc%%e\n\tx\n\tx\nz\n"
// The commands can be scattered between separate invocations of Format(),
// i.e. the formatter keeps track of the indent level and knows if it is
// positioned on start of a line and should emit indentation(s).
// The same output as above can be produced by e.g.:
// f := IndentFormatter(os.Stdout, " ")
// f.Format("abc%d%%e%i\nx\n", 3)
// f.Format("y\n%uz\n")
func IndentFormatter(w io.Writer, indent string) Formatter {
return &indentFormatter{w, []byte(indent), 0, stBOL}
}
func (f *indentFormatter) format(flat bool, format string, args ...interface{}) (n int, errno error) {
buf := []byte{}
for i := 0; i < len(format); i++ {
c := format[i]
switch f.state {
case st0:
switch c {
case '\n':
cc := c
if flat && f.indentLevel != 0 {
cc = ' '
}
buf = append(buf, cc)
f.state = stBOL
case '%':
f.state = stPERC
default:
buf = append(buf, c)
}
case stBOL:
switch c {
case '\n':
cc := c
if flat && f.indentLevel != 0 {
cc = ' '
}
buf = append(buf, cc)
case '%':
f.state = stBOLPERC
default:
if !flat {
for i := 0; i < f.indentLevel; i++ {
buf = append(buf, f.indent...)
}
}
buf = append(buf, c)
f.state = st0
}
case stBOLPERC:
switch c {
case 'i':
f.indentLevel++
f.state = stBOL
case 'u':
f.indentLevel--
f.state = stBOL
default:
if !flat {
for i := 0; i < f.indentLevel; i++ {
buf = append(buf, f.indent...)
}
}
buf = append(buf, '%', c)
f.state = st0
}
case stPERC:
switch c {
case 'i':
f.indentLevel++
f.state = st0
case 'u':
f.indentLevel--
f.state = st0
default:
buf = append(buf, '%', c)
f.state = st0
}
default:
panic("unexpected state")
}
}
switch f.state {
case stPERC, stBOLPERC:
buf = append(buf, '%')
}
return f.Write([]byte(fmt.Sprintf(string(buf), args...)))
}
func (f *indentFormatter) Format(format string, args ...interface{}) (n int, errno error) {
return f.format(false, format, args...)
}
type flatFormatter indentFormatter
// FlatFormatter returns a newly created Formatter with the same functionality as the one returned
// by IndentFormatter except it allows a newline in the 'format' string argument of Format
// to pass through iff indent level is currently zero.
//
// If indent level is non-zero then such new lines are changed to a space character.
// There is no indent string, the %i and %u format verbs are used solely to determine the indent level.
//
// The FlatFormatter is intended for flattening of normally nested structure textual representation to
// a one top level structure per line form.
// FlatFormatter(os.Stdout, " ").Format("abc%d%%e%i\nx\ny\n%uz\n", 3)
// output in the form of a Go quoted string literal:
// "abc3%%e x y z\n"
func FlatFormatter(w io.Writer) Formatter {
return (*flatFormatter)(IndentFormatter(w, "").(*indentFormatter))
}
func (f *flatFormatter) Format(format string, args ...interface{}) (n int, errno error) {
return (*indentFormatter)(f).format(true, format, args...)
}
// Pool handles aligning of strings having equal values to the same string instance.
// Intended use is to conserve some memory e.g. where a large number of identically valued strings
// with non identical backing arrays may exists in several semantically distinct instances of some structs.
// Pool is *not* concurrent access safe. It doesn't handle common prefix/suffix aligning,
// e.g. having s1 == "abc" and s2 == "bc", s2 is not automatically aligned as s1[1:].
type Pool struct {
pool map[string]string
}
// NewPool returns a newly created Pool.
func NewPool() *Pool {
return &Pool{map[string]string{}}
}
// Align returns a string with the same value as its argument. It guarantees that
// all aligned strings share a single instance in memory.
func (p *Pool) Align(s string) string {
if a, ok := p.pool[s]; ok {
return a
}
s = StrPack(s)
p.pool[s] = s
return s
}
// Count returns the number of items in the pool.
func (p *Pool) Count() int {
return len(p.pool)
}
// GoPool is a concurrent access safe version of Pool.
type GoPool struct {
pool map[string]string
rwm *sync.RWMutex
}
// NewGoPool returns a newly created GoPool.
func NewGoPool() (p *GoPool) {
return &GoPool{map[string]string{}, &sync.RWMutex{}}
}
// Align returns a string with the same value as its argument. It guarantees that
// all aligned strings share a single instance in memory.
func (p *GoPool) Align(s string) (y string) {
if s != "" {
p.rwm.RLock() // R++
if a, ok := p.pool[s]; ok { // found
p.rwm.RUnlock() // R--
return a
}
p.rwm.RUnlock() // R--
// not found but with a race condition, retry within a write lock
p.rwm.Lock() // W++
defer p.rwm.Unlock() // W--
if a, ok := p.pool[s]; ok { // done in a race
return a
}
// we won
s = StrPack(s)
p.pool[s] = s
return s
}
return
}
// Count returns the number of items in the pool.
func (p *GoPool) Count() int {
return len(p.pool)
}
// Dict is a string <-> id bijection. Dict is *not* concurrent access safe for assigning new ids
// to strings not yet contained in the bijection.
// Id for an empty string is guaranteed to be 0,
// thus Id for any non empty string is guaranteed to be non zero.
type Dict struct {
si map[string]int
is []string
}
// NewDict returns a newly created Dict.
func NewDict() (d *Dict) {
d = &Dict{map[string]int{}, []string{}}
d.Id("")
return
}
// Count returns the number of items in the dict.
func (d *Dict) Count() int {
return len(d.is)
}
// Id maps string s to its numeric identificator.
func (d *Dict) Id(s string) (y int) {
if y, ok := d.si[s]; ok {
return y
}
s = StrPack(s)
y = len(d.is)
d.si[s] = y
d.is = append(d.is, s)
return
}
// S maps an id to its string value and ok == true. Id values not contained in the bijection
// return "", false.
func (d *Dict) S(id int) (s string, ok bool) {
if id >= len(d.is) {
return "", false
}
return d.is[id], true
}
// GoDict is a concurrent access safe version of Dict.
type GoDict struct {
si map[string]int
is []string
rwm *sync.RWMutex
}
// NewGoDict returns a newly created GoDict.
func NewGoDict() (d *GoDict) {
d = &GoDict{map[string]int{}, []string{}, &sync.RWMutex{}}
d.Id("")
return
}
// Count returns the number of items in the dict.
func (d *GoDict) Count() int {
return len(d.is)
}
// Id maps string s to its numeric identificator. The implementation honors getting
// an existing id at the cost of assigning a new one.
func (d *GoDict) Id(s string) (y int) {
d.rwm.RLock() // R++
if y, ok := d.si[s]; ok { // found
d.rwm.RUnlock() // R--
return y
}
d.rwm.RUnlock() // R--
// not found but with a race condition
d.rwm.Lock() // W++ recheck with write lock
defer d.rwm.Unlock() // W--
if y, ok := d.si[s]; ok { // some other goroutine won already
return y
}
// a race free not found state => insert the string
s = StrPack(s)
y = len(d.is)
d.si[s] = y
d.is = append(d.is, s)
return
}
// S maps an id to its string value and ok == true. Id values not contained in the bijection
// return "", false.
func (d *GoDict) S(id int) (s string, ok bool) {
d.rwm.RLock() // R++
defer d.rwm.RUnlock() // R--
if id >= len(d.is) {
return "", false
}
return d.is[id], true
}
// StrPack returns a new instance of s which is tightly packed in memory.
// It is intended for avoiding the situation where having a live reference
// to a string slice over an unreferenced biger underlying string keeps the biger one
// in memory anyway - it can't be GCed.
func StrPack(s string) string {
return string([]byte(s)) // T(U(T)) intentional.
}
// JoinFields returns strings in flds joined by sep. Flds may contain arbitrary
// bytes, including the sep as they are safely escaped. JoinFields panics if
// sep is the backslash character or if len(sep) != 1.
func JoinFields(flds []string, sep string) string {
if len(sep) != 1 || sep == "\\" {
panic("invalid separator")
}
a := make([]string, len(flds))
for i, v := range flds {
v = strings.Replace(v, "\\", "\\0", -1)
a[i] = strings.Replace(v, sep, "\\1", -1)
}
return strings.Join(a, sep)
}
// SplitFields splits s, which must be produced by JoinFields using the same
// sep, into flds. SplitFields panics if sep is the backslash character or if
// len(sep) != 1.
func SplitFields(s, sep string) (flds []string) {
if len(sep) != 1 || sep == "\\" {
panic("invalid separator")
}
a := strings.Split(s, sep)
r := make([]string, len(a))
for i, v := range a {
v = strings.Replace(v, "\\1", sep, -1)
r[i] = strings.Replace(v, "\\0", "\\", -1)
}
return r
}
// PrettyPrintHooks allow to customize the result of PrettyPrint for types
// listed in the map value.
type PrettyPrintHooks map[reflect.Type]func(f Formatter, v interface{}, prefix, suffix string)
// PrettyString returns the output of PrettyPrint as a string.
func PrettyString(v interface{}, prefix, suffix string, hooks PrettyPrintHooks) string {
var b bytes.Buffer
PrettyPrint(&b, v, prefix, suffix, hooks)
return b.String()
}
// PrettyPrint pretty prints v to w. Zero values and unexported struct fields
// are omitted.
//
// Force printing of zero values of struct fields by including in the field tag
// PrettyPrint:"zero".
//
// Enable using a String method, if any, of a struct field type by including in
// the field tag PrettyPrint:"stringer".
//
// The tags can be combined as in PrettyPrint:"zero,stringer". The order is not
// important, so PrettyPrint:stringer,zero has the same effect.
//
// A hook attached to the field type has priority over the struct field tag
// described above.
func PrettyPrint(w io.Writer, v interface{}, prefix, suffix string, hooks PrettyPrintHooks) {
if v == nil {
return
}
f := IndentFormatter(w, "· ")
defer func() {
if e := recover(); e != nil {
f.Format("\npanic: %v", e)
}
}()
prettyPrint(nil, f, prefix, suffix, v, hooks, false, false)
}
func prettyPrint(protect map[interface{}]struct{}, sf Formatter, prefix, suffix string, v interface{}, hooks PrettyPrintHooks, zero, stringer bool) {
if v == nil {
return
}
rt := reflect.TypeOf(v)
if handler := hooks[rt]; handler != nil {
handler(sf, v, prefix, suffix)
return
}
rv := reflect.ValueOf(v)
if stringer {
if _, ok := v.(fmt.Stringer); ok {
sf.Format("%s%s", prefix, v)
sf.Format(suffix)
return
}
}
switch rt.Kind() {
case reflect.Slice:
if rv.Len() == 0 && !zero {
return
}
sf.Format("%s[]%T{ // len %d%i\n", prefix, rv.Index(0).Interface(), rv.Len())
for i := 0; i < rv.Len(); i++ {
prettyPrint(protect, sf, fmt.Sprintf("%d: ", i), ",\n", rv.Index(i).Interface(), hooks, false, false)
}
suffix = strings.Replace(suffix, "%", "%%", -1)
sf.Format("%u}" + suffix)
case reflect.Array:
if reflect.Zero(rt).Interface() == rv.Interface() && !zero {
return
}
sf.Format("%s[%d]%T{%i\n", prefix, rv.Len(), rv.Index(0).Interface())
for i := 0; i < rv.Len(); i++ {
prettyPrint(protect, sf, fmt.Sprintf("%d: ", i), ",\n", rv.Index(i).Interface(), hooks, false, false)
}
suffix = strings.Replace(suffix, "%", "%%", -1)
sf.Format("%u}" + suffix)
case reflect.Struct:
if rt.NumField() == 0 {
return
}
if reflect.DeepEqual(reflect.Zero(rt).Interface(), rv.Interface()) && !zero {
return
}
sf.Format("%s%T{%i\n", prefix, v)
for i := 0; i < rt.NumField(); i++ {
f := rv.Field(i)
if !f.CanInterface() {
continue
}
var stringer, zero bool
ft := rt.Field(i)
if tag, ok := ft.Tag.Lookup("PrettyPrint"); ok {
a := strings.Split(tag, ",")
for _, v := range a {
switch strings.TrimSpace(v) {
case "stringer":
stringer = true
case "zero":
zero = true
}
}
}
prettyPrint(protect, sf, fmt.Sprintf("%s: ", rt.Field(i).Name), ",\n", f.Interface(), hooks, zero, stringer)
}
suffix = strings.Replace(suffix, "%", "%%", -1)
sf.Format("%u}" + suffix)
case reflect.Ptr:
if rv.IsNil() && !zero {
return
}
rvi := rv.Interface()
if _, ok := protect[rvi]; ok {
suffix = strings.Replace(suffix, "%", "%%", -1)
sf.Format("%s&%T{ /* recursive/repetitive pointee not shown */ }"+suffix, prefix, rv.Elem().Interface())
return
}
if protect == nil {
protect = map[interface{}]struct{}{}
}
protect[rvi] = struct{}{}
prettyPrint(protect, sf, prefix+"&", suffix, rv.Elem().Interface(), hooks, false, false)
case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int8:
if v := rv.Int(); v != 0 || zero {
suffix = strings.Replace(suffix, "%", "%%", -1)
sf.Format("%s%v"+suffix, prefix, v)
}
case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint8:
if v := rv.Uint(); v != 0 || zero {
suffix = strings.Replace(suffix, "%", "%%", -1)
sf.Format("%s%v"+suffix, prefix, v)
}
case reflect.Float32, reflect.Float64:
if v := rv.Float(); v != 0 || zero {
suffix = strings.Replace(suffix, "%", "%%", -1)
sf.Format("%s%v"+suffix, prefix, v)
}
case reflect.Complex64, reflect.Complex128:
if v := rv.Complex(); v != 0 || zero {
suffix = strings.Replace(suffix, "%", "%%", -1)
sf.Format("%s%v"+suffix, prefix, v)
}
case reflect.Uintptr:
if v := rv.Uint(); v != 0 || zero {
suffix = strings.Replace(suffix, "%", "%%", -1)
sf.Format("%s%v"+suffix, prefix, v)
}
case reflect.UnsafePointer:
s := fmt.Sprintf("%p", rv.Interface())
if s == "0x0" && !zero {
return
}
suffix = strings.Replace(suffix, "%", "%%", -1)
sf.Format("%s%s"+suffix, prefix, s)
case reflect.Bool:
if v := rv.Bool(); v || zero {
suffix = strings.Replace(suffix, "%", "%%", -1)
sf.Format("%s%v"+suffix, prefix, rv.Bool())
}
case reflect.String:
s := rv.Interface().(string)
if s == "" && !zero {
return
}
suffix = strings.Replace(suffix, "%", "%%", -1)
sf.Format("%s%q"+suffix, prefix, s)
case reflect.Chan:
if reflect.Zero(rt).Interface() == rv.Interface() && !zero {
return
}
c := rv.Cap()
s := ""
if c != 0 {
s = fmt.Sprintf("// capacity: %d", c)
}
suffix = strings.Replace(suffix, "%", "%%", -1)
sf.Format("%s%s %s%s"+suffix, prefix, rt.ChanDir(), rt.Elem().Name(), s)
case reflect.Func:
if rv.IsNil() && !zero {
return
}
var in, out []string
for i := 0; i < rt.NumIn(); i++ {
x := reflect.Zero(rt.In(i))
in = append(in, fmt.Sprintf("%T", x.Interface()))
}
if rt.IsVariadic() {
i := len(in) - 1
in[i] = "..." + in[i][2:]
}
for i := 0; i < rt.NumOut(); i++ {
out = append(out, rt.Out(i).Name())
}
s := "(" + strings.Join(in, ", ") + ")"
t := strings.Join(out, ", ")
if len(out) > 1 {
t = "(" + t + ")"
}
if t != "" {
t = " " + t
}
suffix = strings.Replace(suffix, "%", "%%", -1)
sf.Format("%sfunc%s%s { ... }"+suffix, prefix, s, t)
case reflect.Map:
keys := rv.MapKeys()
if len(keys) == 0 && !zero {
return
}
var buf bytes.Buffer
nf := IndentFormatter(&buf, "· ")
var skeys []string
for i, k := range keys {
prettyPrint(protect, nf, "", "", k.Interface(), hooks, false, false)
skeys = append(skeys, fmt.Sprintf("%s%10d", buf.Bytes(), i))
buf.Reset()
}
sort.Strings(skeys)
sf.Format("%s%T{%i\n", prefix, v)
for _, k := range skeys {
si := strings.TrimSpace(k[len(k)-10:])
k = k[:len(k)-10]
n, _ := strconv.ParseUint(si, 10, 64)
mv := rv.MapIndex(keys[n])
prettyPrint(protect, sf, fmt.Sprintf("%s: ", k), ",\n", mv.Interface(), hooks, false, false)
}
suffix = strings.Replace(suffix, "%", "%%", -1)
sf.Format("%u}" + suffix)
}
}
// Gopath returns the value of the $GOPATH environment variable or its default
// value if not set.
func Gopath() string {
if r := os.Getenv("GOPATH"); r != "" {
return r
}
// go1.8: https://github.com/golang/go/blob/74628a8b9f102bddd5078ee426efe0fd57033115/doc/code.html#L122
switch runtime.GOOS {
case "plan9":
return os.Getenv("home")
case "windows":
return filepath.Join(os.Getenv("USERPROFILE"), "go")
default:
return filepath.Join(os.Getenv("HOME"), "go")
}
}
// Homepath returns the user's home directory path.
func Homepath() string {
// go1.8: https://github.com/golang/go/blob/74628a8b9f102bddd5078ee426efe0fd57033115/doc/code.html#L122
switch runtime.GOOS {
case "plan9":
return os.Getenv("home")
case "windows":
return os.Getenv("USERPROFILE")
default:
return os.Getenv("HOME")
}
}
// ImportPath returns the import path of the caller or an error, if any.
func ImportPath() (string, error) {
_, file, _, ok := runtime.Caller(1)
if !ok {
return "", fmt.Errorf("runtime.Caller failed")
}
gopath := Gopath()
for _, v := range filepath.SplitList(gopath) {
gp := filepath.Join(v, "src")
path, err := filepath.Rel(gp, file)
if err != nil {
continue
}
return filepath.Dir(path), nil
}
return "", fmt.Errorf("cannot determine import path using GOPATH=%s", gopath)
}