<commit_before>package vm

import (
	"fmt"
	"strconv"
	"strings"
	"unicode"
)

var (
	stringClass *RString
)

// RString is the built in string class
type RString struct {
	*BaseClass
}

// StringObject represents string instances
// String object holds and manipulates a sequence of characters.
// String objects may be created using as string literals.
// Double or single quotations can be used for representation.
//
// ```ruby
// a = "Three"
// b = 'zero'
// c = '漢'
// d = 'Tiếng Việt'
// e = "😏"
// ```
//
// **Note:**
//
// - Currently, manipulations are based upon Golang's Unicode manipulations.
// - Currently, UTF-8 encoding is assumed based upon Golang's string manipulation, but the encoding is not actually specified(TBD).
// - `String.new` is not supported.
type StringObject struct {
	Class *RString
	Value string
}

func (s *StringObject) toString() string {
	return "\"" + s.Value + "\""
}

func (s *StringObject) toJSON() string {
	return "\"" + s.Value + "\""
}

func (s *StringObject) returnClass() Class {
	if s.Class == nil {
		panic(fmt.Sprintf("String %s doesn't have class.", s.toString()))
	}

	return s.Class
}

func (s *StringObject) equal(e *StringObject) bool {
	return s.Value == e.Value
}

func initStringObject(value string) *StringObject {
	value = strings.Replace(value, "\\n", "\n", -1)
	value = strings.Replace(value, "\\r", "\r", -1)
	value = strings.Replace(value, "\\t", "\t", -1)
	value = strings.Replace(value, "\\v", "\v", -1)
	value = strings.Replace(value, "\\\\", "\\", -1)
	return &StringObject{Value: value, Class: stringClass}
}

var builtinStringInstanceMethods = []*BuiltInMethodObject{
	{
		// Returns the concatenation of self and another String
		//
		// ```Ruby
		// "first" + "-second" # => "first-second"
		// ```
		//
		// @return [String]
		Name: "+",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				leftValue := receiver.(*StringObject).Value
				right, ok := args[0].(*StringObject)

				if !ok {
					return wrongTypeError(stringClass)
				}

				rightValue := right.Value
				return &StringObject{Value: leftValue + rightValue, Class: stringClass}
			}
		},
	},
	{
		// Returns self multiplying another Integer
		//
		// ```Ruby
		// "string " * 2 # => "string string string "
		// ```
		//
		// @return [String]
		Name: "*",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				leftValue := receiver.(*StringObject).Value
				right, ok := args[0].(*IntegerObject)

				if !ok {
					return wrongTypeError(stringClass)
				}

				if right.Value < 0 {
					return newError("Second argument must be greater than or equal to 0 String#*")
				}

				var result string

				for i := 0; i < right.Value; i++ {
					result += leftValue
				}

				return &StringObject{Value: result, Class: stringClass}
			}
		},
	},
	{
		// Returns a Boolean if first string greater than second string
		//
		// ```Ruby
		// "a" < "b" # => true
		// ```
		//
		// @return [Boolean]
		Name: ">",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				leftValue := receiver.(*StringObject).Value
				right, ok := args[0].(*StringObject)

				if !ok {
					return wrongTypeError(stringClass)
				}

				rightValue := right.Value

				if leftValue > rightValue {
					return TRUE
				}

				return FALSE
			}
		},
	},
	{
		// Returns a Boolean if first string less than second string
		//
		// ```Ruby
		// "a" < "b" # => true
		// ```
		//
		// @return [Boolean]
		Name: "<",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				leftValue := receiver.(*StringObject).Value
				right, ok := args[0].(*StringObject)

				if !ok {
					return wrongTypeError(stringClass)
				}

				rightValue := right.Value

				if leftValue < rightValue {
					return TRUE
				}

				return FALSE
			}
		},
	},
	{
		// Returns a Boolean of compared two strings
		//
		// ```Ruby
		// "first" == "second" # => false
		// "two" == "two" # => true
		// ```
		//
		// @return [Boolean]
		Name: "==",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				leftValue := receiver.(*StringObject).Value
				right, ok := args[0].(*StringObject)

				if !ok {
					return wrongTypeError(stringClass)
				}

				rightValue := right.Value

				if leftValue == rightValue {
					return TRUE
				}

				return FALSE
			}
		},
	},
	{
		// Returns a Integer. If first string is less than second string returns -1, if equal to returns 0, if greater returns 1
		//
		//
		// ```Ruby
		// "abc" <=> "abcd" # => -1
		// "abc" <=> "abc" # => 0
		// "abcd" <=> "abc" # => 1
		// ```
		//
		// @return [Integer]
		Name: "<=>",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				leftValue := receiver.(*StringObject).Value
				right, ok := args[0].(*StringObject)

				if !ok {
					return wrongTypeError(stringClass)
				}

				rightValue := right.Value

				if leftValue < rightValue {
					return initIntegerObject(-1)
				}
				if leftValue > rightValue {
					return initIntegerObject(1)
				}

				return initIntegerObject(0)
			}
		},
	},
	{
		// Returns a Boolean of compared two strings
		//
		// ```Ruby
		// "first" != "second" # => true
		// "two" != "two" # => false
		// ```
		//
		// @return [Boolean]
		Name: "!=",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				leftValue := receiver.(*StringObject).Value
				right, ok := args[0].(*StringObject)

				if !ok {
					return wrongTypeError(stringClass)
				}

				rightValue := right.Value

				if leftValue != rightValue {
					return TRUE
				}

				return FALSE
			}
		},
	},
	{
		// Return a new String with the first character converted to uppercase but the rest of string converted to lowercase.
		//
		// ```Ruby
		// "test".capitalize         # => "Test"
		// "tEST".capitalize         # => "Test"
		// "heLlo\nWoRLd".capitalize # => "Hello\nworld"
		// ```
		//
		// @return [String]
		Name: "capitalize",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				str := []byte(receiver.(*StringObject).Value)
				start := string(str[0])
				rest := string(str[1:])
				result := strings.ToUpper(start) + strings.ToLower(rest)

				return initStringObject(result)
			}
		},
	},
	{
		// Returns a new String with all characters is upcase
		//
		// ```Ruby
		// "very big".upcase # => "VERY BIG"
		// ```
		//
		// @return [String]
		Name: "upcase",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				str := receiver.(*StringObject).Value

				return initStringObject(strings.ToUpper(str))
			}
		},
	},
	{
		// Returns a new String with all characters is lowercase
		//
		// ```Ruby
		// "erROR".downcase        # => "error"
		// "HeLlO\tWorLD".downcase # => "hello\tworld"
		// ```
		//
		// @return [String]
		Name: "downcase",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				str := receiver.(*StringObject).Value

				return initStringObject(strings.ToLower(str))
			}
		},
	},
	{
		// Returns the character length of self
		// **Note:** the length is currently byte-based, instead of charcode-based.
		//
		// ```Ruby
		// "zero".size # => 4
		// "".size # => 0
		// ```
		//
		// @return [Integer]
		Name: "size",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				str := receiver.(*StringObject).Value

				return initIntegerObject(len(str))
			}
		},
	},
	{
		// Returns the character length of self
		// **Note:** the length is currently byte-based, instead of charcode-based.
		//
		// ```Ruby
		// "zero".size # => 4
		// "".size # => 0
		// ```
		//
		// @return [Integer]
		Name: "length",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				str := receiver.(*StringObject).Value

				return initIntegerObject(len(str))
			}
		},
	},
	{
		// Returns a new String with reverse order of self
		// **Note:** the length is currently byte-based, instead of charcode-based.
		//
		// ```Ruby
		// "reverse".reverse      # => "esrever"
		// "Hello\nWorld".reverse # => "dlroW\nolleH"
		// ```
		//
		// @return [String]
		Name: "reverse",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				str := receiver.(*StringObject).Value

				var revert string
				for i := len(str) - 1; i >= 0; i-- {
					revert += string(str[i])
				}

				return initStringObject(revert)
			}
		},
	},
	{
		// Returns a new String with self value
		//
		// ```Ruby
		// "string".to_s # => "string"
		// ```
		//
		// @return [String]
		Name: "to_s",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				str := receiver.(*StringObject).Value

				return initStringObject(str)
			}
		},
	},
	{
		// Returns the result of converting self to Integer
		//
		// ```Ruby
		// "123".to_i # => 123
		// "3d print".to_i # => 3
		// "some text".to_i # => 0
		// ```
		//
		// @return [Integer]
		Name: "to_i",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				str := receiver.(*StringObject).Value
				parsedStr, err := strconv.ParseInt(str, 10, 0)

				if err == nil {
					return initIntegerObject(int(parsedStr))
				}

				var digits string
				for _, char := range str {
					if unicode.IsDigit(char) {
						digits += string(char)
					} else {
						break
					}
				}

				if len(digits) > 0 {
					parsedStr, _ = strconv.ParseInt(digits, 10, 0)
					return initIntegerObject(int(parsedStr))
				}

				return initIntegerObject(0)
			}
		},
	},
	{
		// Checks if the specified string is included in the receiver
		//
		// ```Ruby
		// "Hello\nWorld".include("\n") # => true
		// ```
		//
		// @return [Bool]
		Name: "include",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				rcv := receiver.(*StringObject).Value
				arg := args[0].(*StringObject).Value

				if strings.Contains(rcv, arg) {
					return TRUE
				}

				return FALSE
			}
		},
	},
}

func initStringClass() {
	bc := &BaseClass{Name: "String", Methods: newEnvironment(), ClassMethods: newEnvironment(), Class: classClass, pseudoSuperClass: objectClass, superClass: objectClass}
	sc := &RString{BaseClass: bc}
	sc.setBuiltInMethods(builtinStringInstanceMethods, false)
	stringClass = sc
}
<commit_msg>Change string replacer to efficient version<commit_after>package vm

import (
	"fmt"
	"strconv"
	"strings"
	"unicode"
)

var (
	stringClass *RString
)

// RString is the built in string class
type RString struct {
	*BaseClass
}

// StringObject represents string instances
// String object holds and manipulates a sequence of characters.
// String objects may be created using as string literals.
// Double or single quotations can be used for representation.
//
// ```ruby
// a = "Three"
// b = 'zero'
// c = '漢'
// d = 'Tiếng Việt'
// e = "😏"
// ```
//
// **Note:**
//
// - Currently, manipulations are based upon Golang's Unicode manipulations.
// - Currently, UTF-8 encoding is assumed based upon Golang's string manipulation, but the encoding is not actually specified(TBD).
// - `String.new` is not supported.
type StringObject struct {
	Class *RString
	Value string
}

func (s *StringObject) toString() string {
	return "\"" + s.Value + "\""
}

func (s *StringObject) toJSON() string {
	return "\"" + s.Value + "\""
}

func (s *StringObject) returnClass() Class {
	if s.Class == nil {
		panic(fmt.Sprintf("String %s doesn't have class.", s.toString()))
	}

	return s.Class
}

func (s *StringObject) equal(e *StringObject) bool {
	return s.Value == e.Value
}

func initStringObject(value string) *StringObject {
	replacer := strings.NewReplacer("\\n", "\n", "\\r", "\r", "\\t", "\t", "\\v", "\v", "\\\\", "\\")
	return &StringObject{Value: replacer.Replace(value), Class: stringClass}
}

var builtinStringInstanceMethods = []*BuiltInMethodObject{
	{
		// Returns the concatenation of self and another String
		//
		// ```Ruby
		// "first" + "-second" # => "first-second"
		// ```
		//
		// @return [String]
		Name: "+",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				leftValue := receiver.(*StringObject).Value
				right, ok := args[0].(*StringObject)

				if !ok {
					return wrongTypeError(stringClass)
				}

				rightValue := right.Value
				return &StringObject{Value: leftValue + rightValue, Class: stringClass}
			}
		},
	},
	{
		// Returns self multiplying another Integer
		//
		// ```Ruby
		// "string " * 2 # => "string string string "
		// ```
		//
		// @return [String]
		Name: "*",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				leftValue := receiver.(*StringObject).Value
				right, ok := args[0].(*IntegerObject)

				if !ok {
					return wrongTypeError(stringClass)
				}

				if right.Value < 0 {
					return newError("Second argument must be greater than or equal to 0 String#*")
				}

				var result string

				for i := 0; i < right.Value; i++ {
					result += leftValue
				}

				return &StringObject{Value: result, Class: stringClass}
			}
		},
	},
	{
		// Returns a Boolean if first string greater than second string
		//
		// ```Ruby
		// "a" < "b" # => true
		// ```
		//
		// @return [Boolean]
		Name: ">",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				leftValue := receiver.(*StringObject).Value
				right, ok := args[0].(*StringObject)

				if !ok {
					return wrongTypeError(stringClass)
				}

				rightValue := right.Value

				if leftValue > rightValue {
					return TRUE
				}

				return FALSE
			}
		},
	},
	{
		// Returns a Boolean if first string less than second string
		//
		// ```Ruby
		// "a" < "b" # => true
		// ```
		//
		// @return [Boolean]
		Name: "<",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				leftValue := receiver.(*StringObject).Value
				right, ok := args[0].(*StringObject)

				if !ok {
					return wrongTypeError(stringClass)
				}

				rightValue := right.Value

				if leftValue < rightValue {
					return TRUE
				}

				return FALSE
			}
		},
	},
	{
		// Returns a Boolean of compared two strings
		//
		// ```Ruby
		// "first" == "second" # => false
		// "two" == "two" # => true
		// ```
		//
		// @return [Boolean]
		Name: "==",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				leftValue := receiver.(*StringObject).Value
				right, ok := args[0].(*StringObject)

				if !ok {
					return wrongTypeError(stringClass)
				}

				rightValue := right.Value

				if leftValue == rightValue {
					return TRUE
				}

				return FALSE
			}
		},
	},
	{
		// Returns a Integer. If first string is less than second string returns -1, if equal to returns 0, if greater returns 1
		//
		//
		// ```Ruby
		// "abc" <=> "abcd" # => -1
		// "abc" <=> "abc" # => 0
		// "abcd" <=> "abc" # => 1
		// ```
		//
		// @return [Integer]
		Name: "<=>",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				leftValue := receiver.(*StringObject).Value
				right, ok := args[0].(*StringObject)

				if !ok {
					return wrongTypeError(stringClass)
				}

				rightValue := right.Value

				if leftValue < rightValue {
					return initIntegerObject(-1)
				}
				if leftValue > rightValue {
					return initIntegerObject(1)
				}

				return initIntegerObject(0)
			}
		},
	},
	{
		// Returns a Boolean of compared two strings
		//
		// ```Ruby
		// "first" != "second" # => true
		// "two" != "two" # => false
		// ```
		//
		// @return [Boolean]
		Name: "!=",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				leftValue := receiver.(*StringObject).Value
				right, ok := args[0].(*StringObject)

				if !ok {
					return wrongTypeError(stringClass)
				}

				rightValue := right.Value

				if leftValue != rightValue {
					return TRUE
				}

				return FALSE
			}
		},
	},
	{
		// Return a new String with the first character converted to uppercase but the rest of string converted to lowercase.
		//
		// ```Ruby
		// "test".capitalize         # => "Test"
		// "tEST".capitalize         # => "Test"
		// "heLlo\nWoRLd".capitalize # => "Hello\nworld"
		// ```
		//
		// @return [String]
		Name: "capitalize",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				str := []byte(receiver.(*StringObject).Value)
				start := string(str[0])
				rest := string(str[1:])
				result := strings.ToUpper(start) + strings.ToLower(rest)

				return initStringObject(result)
			}
		},
	},
	{
		// Returns a new String with all characters is upcase
		//
		// ```Ruby
		// "very big".upcase # => "VERY BIG"
		// ```
		//
		// @return [String]
		Name: "upcase",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				str := receiver.(*StringObject).Value

				return initStringObject(strings.ToUpper(str))
			}
		},
	},
	{
		// Returns a new String with all characters is lowercase
		//
		// ```Ruby
		// "erROR".downcase        # => "error"
		// "HeLlO\tWorLD".downcase # => "hello\tworld"
		// ```
		//
		// @return [String]
		Name: "downcase",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				str := receiver.(*StringObject).Value

				return initStringObject(strings.ToLower(str))
			}
		},
	},
	{
		// Returns the character length of self
		// **Note:** the length is currently byte-based, instead of charcode-based.
		//
		// ```Ruby
		// "zero".size # => 4
		// "".size # => 0
		// ```
		//
		// @return [Integer]
		Name: "size",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				str := receiver.(*StringObject).Value

				return initIntegerObject(len(str))
			}
		},
	},
	{
		// Returns the character length of self
		// **Note:** the length is currently byte-based, instead of charcode-based.
		//
		// ```Ruby
		// "zero".size # => 4
		// "".size # => 0
		// ```
		//
		// @return [Integer]
		Name: "length",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				str := receiver.(*StringObject).Value

				return initIntegerObject(len(str))
			}
		},
	},
	{
		// Returns a new String with reverse order of self
		// **Note:** the length is currently byte-based, instead of charcode-based.
		//
		// ```Ruby
		// "reverse".reverse      # => "esrever"
		// "Hello\nWorld".reverse # => "dlroW\nolleH"
		// ```
		//
		// @return [String]
		Name: "reverse",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				str := receiver.(*StringObject).Value

				var revert string
				for i := len(str) - 1; i >= 0; i-- {
					revert += string(str[i])
				}

				return initStringObject(revert)
			}
		},
	},
	{
		// Returns a new String with self value
		//
		// ```Ruby
		// "string".to_s # => "string"
		// ```
		//
		// @return [String]
		Name: "to_s",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				str := receiver.(*StringObject).Value

				return initStringObject(str)
			}
		},
	},
	{
		// Returns the result of converting self to Integer
		//
		// ```Ruby
		// "123".to_i # => 123
		// "3d print".to_i # => 3
		// "some text".to_i # => 0
		// ```
		//
		// @return [Integer]
		Name: "to_i",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				str := receiver.(*StringObject).Value
				parsedStr, err := strconv.ParseInt(str, 10, 0)

				if err == nil {
					return initIntegerObject(int(parsedStr))
				}

				var digits string
				for _, char := range str {
					if unicode.IsDigit(char) {
						digits += string(char)
					} else {
						break
					}
				}

				if len(digits) > 0 {
					parsedStr, _ = strconv.ParseInt(digits, 10, 0)
					return initIntegerObject(int(parsedStr))
				}

				return initIntegerObject(0)
			}
		},
	},
	{
		// Checks if the specified string is included in the receiver
		//
		// ```Ruby
		// "Hello\nWorld".include("\n") # => true
		// ```
		//
		// @return [Bool]
		Name: "include",
		Fn: func(receiver Object) builtinMethodBody {
			return func(t *thread, args []Object, blockFrame *callFrame) Object {

				rcv := receiver.(*StringObject).Value
				arg := args[0].(*StringObject).Value

				if strings.Contains(rcv, arg) {
					return TRUE
				}

				return FALSE
			}
		},
	},
}

func initStringClass() {
	bc := &BaseClass{Name: "String", Methods: newEnvironment(), ClassMethods: newEnvironment(), Class: classClass, pseudoSuperClass: objectClass, superClass: objectClass}
	sc := &RString{BaseClass: bc}
	sc.setBuiltInMethods(builtinStringInstanceMethods, false)
	stringClass = sc
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"testing"
	"time"
)

type FakeEvent string

func (s FakeEvent) String() string {
	return string(s)
}

func NewFakeWatcher() *Watcher {
	return &Watcher{
		make(chan fmt.Stringer),
		make(chan error),
	}
}

func (watcher *Watcher) SendCreate() {
	watcher.Event <- FakeEvent(`"/tmp/fake.txt": CREATE`)
}

func TestAppIntegrations(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping application integration testing.")
	}

	// essential setup commands
	*shell = "/bin/sh"

	subStdin, unsubStdin = ManageUserInput(os.Stdin)

	t.Run("Simple", appSimple)
	t.Run("EventRace", appEventRace)
	t.Run("Daemon", appDaemon)
	t.Run("DaemonTimer", appDaemonTimer)
}

func appSimple(t *testing.T) {
	*buildCmd = "echo testsimple"

	watcher := NewFakeWatcher()

	quit := make(chan struct{})

	go func() {
		duration := time.Duration(1) * time.Second
		for {
			select {
			case <-quit:
				return
			default:
			}

			watcher.Event <- FakeEvent(`"/tmp/fake.txt": CREATE`)
			time.Sleep(duration)
			duration += time.Second
		}
	}()

	go func() {
		time.Sleep(time.Duration(3 * time.Second))
		close(quit)
	}()

	runChain(watcher, quit)
	*buildCmd = ""
}

func appEventRace(t *testing.T) {
	*buildCmd = "echo echonow"

	watcher := NewFakeWatcher()

	quit := make(chan struct{})

	go func() {
		duration := time.Duration(1)
		for {
			select {
			case <-quit:
				return
			default:
			}

			watcher.Event <- FakeEvent(`"/tmp/fake.txt": CREATE`)
			time.Sleep(duration)
			duration += 10
		}
	}()

	go func() {
		time.Sleep(time.Duration(1 * time.Second))
		close(quit)
	}()

	runChain(watcher, quit)
	*buildCmd = ""
}

func appDaemon(t *testing.T) {
	*daemonCmd = "sleep 1s && echo testdaemonOut1 && sleep 2s && echo testdaemonOut2"
	watcher := NewFakeWatcher()

	quit := make(chan struct{})
	go func() {
		time.Sleep(time.Duration(1 * time.Second))
		watcher.SendCreate()
		time.Sleep(time.Duration(2 * time.Second))
		watcher.SendCreate()
		time.Sleep(time.Duration(4 * time.Second))
		close(quit)
	}()

	runChain(watcher, quit)
	*daemonCmd = ""
}

func appDaemonTimer(t *testing.T) {
	*daemonCmd = "sleep 1s && echo testdaemontimerOut1 && sleep 2s && echo testdaemontimerOut2"
	*daemonTimer = 2 * int(time.Second)

	watcher := NewFakeWatcher()

	quit := make(chan struct{})
	go func() {
		time.Sleep(time.Duration(1 * time.Second))
		watcher.SendCreate()
		time.Sleep(time.Duration(4 * time.Second))
		watcher.SendCreate()
		time.Sleep(time.Duration(4 * time.Second))
		close(quit)
	}()

	runChain(watcher, quit)
	*daemonCmd = ""
	*daemonTimer = 0
}
<commit_msg>update tests for fsnotify 1.0<commit_after>package main

import (
	"os"
	"testing"
	"time"

	"github.com/fsnotify/fsnotify"
)

func NewFakeWatcher() *Watcher {
	return &Watcher{
		make(chan fsnotify.Event),
		make(chan error),
	}
}

func (watcher *Watcher) SendCreate() {
	watcher.Event <- fsnotify.Event{`"/tmp/fake.txt": CREATE`, fsnotify.Create}
}

func TestAppIntegrations(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping application integration testing.")
	}

	// essential setup commands
	*shell = "/bin/sh"

	subStdin, unsubStdin = ManageUserInput(os.Stdin)

	t.Run("Simple", appSimple)
	t.Run("EventRace", appEventRace)
	t.Run("Daemon", appDaemon)
	t.Run("DaemonTimer", appDaemonTimer)
}

func appSimple(t *testing.T) {
	*buildCmd = "echo testsimple"

	watcher := NewFakeWatcher()

	quit := make(chan struct{})

	go func() {
		duration := time.Duration(1) * time.Second
		for {
			select {
			case <-quit:
				return
			default:
			}

			watcher.Event <- fsnotify.Event{`"/tmp/fake.txt": CREATE`, fsnotify.Create}
			time.Sleep(duration)
			duration += time.Second
		}
	}()

	go func() {
		time.Sleep(time.Duration(3 * time.Second))
		close(quit)
	}()

	runChain(watcher, quit)
	*buildCmd = ""
}

func appEventRace(t *testing.T) {
	*buildCmd = "echo echonow"

	watcher := NewFakeWatcher()

	quit := make(chan struct{})

	go func() {
		duration := time.Duration(1)
		for {
			select {
			case <-quit:
				return
			default:
			}

			watcher.Event <- fsnotify.Event{`"/tmp/fake.txt": CREATE`, fsnotify.Create}
			time.Sleep(duration)
			duration += 10
		}
	}()

	go func() {
		time.Sleep(time.Duration(1 * time.Second))
		close(quit)
	}()

	runChain(watcher, quit)
	*buildCmd = ""
}

func appDaemon(t *testing.T) {
	*daemonCmd = "sleep 1s && echo testdaemonOut1 && sleep 2s && echo testdaemonOut2"
	watcher := NewFakeWatcher()

	quit := make(chan struct{})
	go func() {
		time.Sleep(time.Duration(1 * time.Second))
		watcher.SendCreate()
		time.Sleep(time.Duration(2 * time.Second))
		watcher.SendCreate()
		time.Sleep(time.Duration(4 * time.Second))
		close(quit)
	}()

	runChain(watcher, quit)
	*daemonCmd = ""
}

func appDaemonTimer(t *testing.T) {
	*daemonCmd = "sleep 1s && echo testdaemontimerOut1 && sleep 2s && echo testdaemontimerOut2"
	*daemonTimer = 2 * int(time.Second)

	watcher := NewFakeWatcher()

	quit := make(chan struct{})
	go func() {
		time.Sleep(time.Duration(1 * time.Second))
		watcher.SendCreate()
		time.Sleep(time.Duration(4 * time.Second))
		watcher.SendCreate()
		time.Sleep(time.Duration(4 * time.Second))
		close(quit)
	}()

	runChain(watcher, quit)
	*daemonCmd = ""
	*daemonTimer = 0
}
<|endoftext|>


<commit_before>package acceptance_test

import (
	"fmt"
	"time"

	yaml "gopkg.in/yaml.v2"

	acceptance "github.com/cloudfoundry/bosh-bootloader/acceptance-tests"
	"github.com/cloudfoundry/bosh-bootloader/acceptance-tests/actors"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
)

const ipRegex = `[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}`

var _ = FDescribe("bosh deployment vars", func() {
	var (
		bbl           actors.BBL
		state         acceptance.State
		configuration acceptance.Config
	)

	BeforeEach(func() {
		var err error
		configuration, err = acceptance.LoadConfig()
		Expect(err).NotTo(HaveOccurred())

		bbl = actors.NewBBL(configuration.StateFileDir, pathToBBL, configuration, "bosh-deployment-vars-env")
		state = acceptance.NewState(configuration.StateFileDir)

		session := bbl.Up("azure", []string{"--name", bbl.PredefinedEnvID(), "--no-director"})
		Eventually(session, 40*time.Minute).Should(gexec.Exit(0))
	})

	AfterEach(func() {
		session := bbl.Destroy()
		Eventually(session, 10*time.Minute).Should(gexec.Exit())
	})

	It("prints the bosh deployment vars for bosh create-env", func() {
		stdout := bbl.BOSHDeploymentVars()

		var vars struct {
			InternalCIDR         string `yaml:"internal_cidr"`
			InternalGateway      string `yaml:"internal_gw"`
			InternalIP           string `yaml:"internal_ip"`
			DirectorName         string `yaml:"director_name"`
			VNetName             string `yaml:"vnet_name"`
			SubnetName           string `yaml:"subnet_name"`
			SubscriptionID       string `yaml:"subscription_id"`
			TenantID             string `yaml:"tenant_id"`
			ClientID             string `yaml:"client_id"`
			ClientSecret         string `yaml:"client_secret"`
			ResourceGroupName    string `yaml:"resource_group_name"`
			StorageAccountName   string `yaml:"storage_account_name"`
			DefaultSecurityGroup string `yaml:"default_security_group"`
		}

		yaml.Unmarshal([]byte(stdout), &vars)
		// Common
		Expect(vars.InternalCIDR).To(Equal("10.0.0.0/24"))
		Expect(vars.InternalGateway).To(Equal("10.0.0.1"))
		Expect(vars.InternalIP).To(Equal("10.0.0.6"))
		Expect(vars.DirectorName).To(Equal(fmt.Sprintf("bosh-%s", bbl.PredefinedEnvID())))

		// Azure  TODO fix expectations
		Expect(vars.VNetName).To(Equal("bbl-test-bosh-deployment-bosh"))
		Expect(vars.SubnetName).To(Equal("10.0.0.6"))
		Expect(vars.SubscriptionID).To(Equal(configuration.AzureSubscriptionID))
		Expect(vars.TenantID).To(Equal(configuration.AzureTenantID))
		Expect(vars.ClientID).To(Equal(configuration.AzureClientID))
		Expect(vars.ClientSecret).To(Equal(configuration.AzureClientSecret))
		Expect(vars.ResourceGroupName).To(Equal(fmt.Sprintf("bosh-%s", bbl.PredefinedEnvID())))
		Expect(vars.StorageAccountName).To(Equal("bbltestboshdeploymen"))
		Expect(vars.DefaultSecurityGroup).To(Equal("bbl-test-bosh-deployment-bosh"))
	})
})
<commit_msg>Fix assertions for resources named after EnvId and not SimpleEnvId.<commit_after>package acceptance_test

import (
	"fmt"
	"time"

	yaml "gopkg.in/yaml.v2"

	acceptance "github.com/cloudfoundry/bosh-bootloader/acceptance-tests"
	"github.com/cloudfoundry/bosh-bootloader/acceptance-tests/actors"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
)

const ipRegex = `[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}`

var _ = FDescribe("bosh deployment vars", func() {
	var (
		bbl           actors.BBL
		state         acceptance.State
		configuration acceptance.Config
	)

	BeforeEach(func() {
		var err error
		configuration, err = acceptance.LoadConfig()
		Expect(err).NotTo(HaveOccurred())

		bbl = actors.NewBBL(configuration.StateFileDir, pathToBBL, configuration, "bosh-deployment-vars-env")
		state = acceptance.NewState(configuration.StateFileDir)

		session := bbl.Up("azure", []string{"--name", bbl.PredefinedEnvID(), "--no-director"})
		Eventually(session, 40*time.Minute).Should(gexec.Exit(0))
	})

	AfterEach(func() {
		session := bbl.Destroy()
		Eventually(session, 10*time.Minute).Should(gexec.Exit())
	})

	It("prints the bosh deployment vars for bosh create-env", func() {
		stdout := bbl.BOSHDeploymentVars()

		var vars struct {
			InternalCIDR         string `yaml:"internal_cidr"`
			InternalGateway      string `yaml:"internal_gw"`
			InternalIP           string `yaml:"internal_ip"`
			DirectorName         string `yaml:"director_name"`
			VNetName             string `yaml:"vnet_name"`
			SubnetName           string `yaml:"subnet_name"`
			SubscriptionID       string `yaml:"subscription_id"`
			TenantID             string `yaml:"tenant_id"`
			ClientID             string `yaml:"client_id"`
			ClientSecret         string `yaml:"client_secret"`
			ResourceGroupName    string `yaml:"resource_group_name"`
			StorageAccountName   string `yaml:"storage_account_name"`
			DefaultSecurityGroup string `yaml:"default_security_group"`
		}

		yaml.Unmarshal([]byte(stdout), &vars)
		// Common
		Expect(vars.InternalCIDR).To(Equal("10.0.0.0/24"))
		Expect(vars.InternalGateway).To(Equal("10.0.0.1"))
		Expect(vars.InternalIP).To(Equal("10.0.0.6"))
		Expect(vars.DirectorName).To(Equal(fmt.Sprintf("bosh-%s", bbl.PredefinedEnvID())))

		// Azure  TODO fix expectations
		Expect(vars.VNetName).To(Equal("bbl-test-bosh-deployment-vars-env-bosh"))
		Expect(vars.SubnetName).To(Equal("10.0.0.6"))
		Expect(vars.SubscriptionID).To(Equal(configuration.AzureSubscriptionID))
		Expect(vars.TenantID).To(Equal(configuration.AzureTenantID))
		Expect(vars.ClientID).To(Equal(configuration.AzureClientID))
		Expect(vars.ClientSecret).To(Equal(configuration.AzureClientSecret))
		Expect(vars.ResourceGroupName).To(Equal(fmt.Sprintf("bosh-%s", bbl.PredefinedEnvID())))
		Expect(vars.StorageAccountName).To(Equal("bbltestboshdeploymen"))
		Expect(vars.DefaultSecurityGroup).To(Equal("bbl-test-bosh-deployment-vars-env-bosh"))
	})
})
<|endoftext|>


<commit_before>package async

// import "fmt"

func Waterfall(routines []Routine, callbacks ...Done) {
  l := New()
  l.Multiple(routines...)

  l.RunWaterfall(callbacks...)
}

func (l *List) RunWaterfall(callbacks ...Done) {
  fall := fall(l, callbacks...)
  next := next(l, callbacks...)

  l.Wait.Add(l.Len())

  fall(next)
}

func fall(l *List, callbacks ...Done) func(Done, ...interface{}) {
  return func(next Done, args ...interface{}) {
    e := l.Front()
    _, r := l.Remove(e)

    // Run the first waterfall routine and give it the next function, and
    // any arguments that were provided
    go r(next, args...)
    l.Wait.Wait()
  }
}

func next(l *List, callbacks ...Done) Done {
  fall := fall(l, callbacks...)

  return func(err error, args ...interface{}) {
    next := next(l, callbacks...)

    l.Wait.Done()
    if err != nil || l.Len() == 0 {
      // Just in case it's an error, let's make sure we've cleared
      // all of the sync.WaitGroup waits that we initiated.
      for i := 0; i < l.Len(); i++ {
        l.Wait.Done()
      }

      // Send the results to the callbacks
      for i := 0; i < len(callbacks); i++ {
        callbacks[i](err, args...)
      }
      return
    }

    // Run the next waterfall routine with any arguments that were provided
    fall(next, args...)
    return
  }
}
<commit_msg>Remove commented import that isn't used<commit_after>package async

func Waterfall(routines []Routine, callbacks ...Done) {
  l := New()
  l.Multiple(routines...)

  l.RunWaterfall(callbacks...)
}

func (l *List) RunWaterfall(callbacks ...Done) {
  fall := fall(l, callbacks...)
  next := next(l, callbacks...)

  l.Wait.Add(l.Len())

  fall(next)
}

func fall(l *List, callbacks ...Done) func(Done, ...interface{}) {
  return func(next Done, args ...interface{}) {
    e := l.Front()
    _, r := l.Remove(e)

    // Run the first waterfall routine and give it the next function, and
    // any arguments that were provided
    go r(next, args...)
    l.Wait.Wait()
  }
}

func next(l *List, callbacks ...Done) Done {
  fall := fall(l, callbacks...)

  return func(err error, args ...interface{}) {
    next := next(l, callbacks...)

    l.Wait.Done()
    if err != nil || l.Len() == 0 {
      // Just in case it's an error, let's make sure we've cleared
      // all of the sync.WaitGroup waits that we initiated.
      for i := 0; i < l.Len(); i++ {
        l.Wait.Done()
      }

      // Send the results to the callbacks
      for i := 0; i < len(callbacks); i++ {
        callbacks[i](err, args...)
      }
      return
    }

    // Run the next waterfall routine with any arguments that were provided
    fall(next, args...)
    return
  }
}
<|endoftext|>


<commit_before>package apps

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gexec"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	"github.com/cloudfoundry-incubator/cf-test-helpers/helpers"
	"github.com/cloudfoundry/cf-acceptance-tests/helpers/app_helpers"
	"github.com/cloudfoundry/cf-acceptance-tests/helpers/assets"
)

var _ = Describe("Copy app bits", func() {
	var golangAppName string
	var helloWorldAppName string

	BeforeEach(func() {
		golangAppName = generator.PrefixedRandomName("CATS-APP-")
		helloWorldAppName = generator.PrefixedRandomName("CATS-APP-")

		Expect(cf.Cf("push", golangAppName, "--no-start", "-b", config.RubyBuildpackName, "-m", DEFAULT_MEMORY_LIMIT, "-p", assets.NewAssets().Golang, "-d", config.AppsDomain).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		Expect(cf.Cf("push", helloWorldAppName, "--no-start", "-m", DEFAULT_MEMORY_LIMIT, "-p", assets.NewAssets().HelloWorld, "-d", config.AppsDomain).Wait(DEFAULT_TIMEOUT)).To(Exit(0))
	})

	AfterEach(func() {
		app_helpers.AppReport(golangAppName, DEFAULT_TIMEOUT)
		app_helpers.AppReport(helloWorldAppName, DEFAULT_TIMEOUT)

		Expect(cf.Cf("delete", golangAppName, "-f", "-r").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		Expect(cf.Cf("delete", helloWorldAppName, "-f", "-r").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
	})

	It("Copies over the package from the source app to the destination app", func() {
		Expect(cf.Cf("copy-source", helloWorldAppName, golangAppName).Wait(CF_PUSH_TIMEOUT)).To(Exit(0))

		Eventually(func() string {
			return helpers.CurlAppRoot(golangAppName)
		}, DEFAULT_TIMEOUT).Should(ContainSubstring("Hello, world!"))
	})
})
<commit_msg>Update app_bits_copy_test.go<commit_after>package apps

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gexec"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/generator"
	"github.com/cloudfoundry-incubator/cf-test-helpers/helpers"
	"github.com/cloudfoundry/cf-acceptance-tests/helpers/app_helpers"
	"github.com/cloudfoundry/cf-acceptance-tests/helpers/assets"
)

var _ = Describe("Copy app bits", func() {
	var golangAppName string
	var helloWorldAppName string

	BeforeEach(func() {
		golangAppName = generator.PrefixedRandomName("CATS-APP-")
		helloWorldAppName = generator.PrefixedRandomName("CATS-APP-")

		Expect(cf.Cf("push", golangAppName, "--no-start", "-b", config.RubyBuildpackName, "-m", DEFAULT_MEMORY_LIMIT, "-p", assets.NewAssets().Golang, "-d", config.AppsDomain).Wait(CF_PUSH_TIMEOUT)).To(Exit(0))
		Expect(cf.Cf("push", helloWorldAppName, "--no-start", "-m", DEFAULT_MEMORY_LIMIT, "-p", assets.NewAssets().HelloWorld, "-d", config.AppsDomain).Wait(CF_PUSH_TIMEOUT)).To(Exit(0))
	})

	AfterEach(func() {
		app_helpers.AppReport(golangAppName, DEFAULT_TIMEOUT)
		app_helpers.AppReport(helloWorldAppName, DEFAULT_TIMEOUT)

		Expect(cf.Cf("delete", golangAppName, "-f", "-r").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
		Expect(cf.Cf("delete", helloWorldAppName, "-f", "-r").Wait(DEFAULT_TIMEOUT)).To(Exit(0))
	})

	It("Copies over the package from the source app to the destination app", func() {
		Expect(cf.Cf("copy-source", helloWorldAppName, golangAppName).Wait(CF_PUSH_TIMEOUT)).To(Exit(0))

		Eventually(func() string {
			return helpers.CurlAppRoot(golangAppName)
		}, DEFAULT_TIMEOUT).Should(ContainSubstring("Hello, world!"))
	})
})
<|endoftext|>


<commit_before>/*

	auto is a package designed to make it trivial to create MoveTypeConfigs
	for your moves.

	Use Case

	Creating MoveTypeConfig is a necessary part of installing moves on your
	GameManager, but it's verbose and error-prone. You need to create a lot of
	extra structs, and then remember to provide the right properties in your
	config. For example, if you forget IsFixUp: true for a fixup move, your
	game logic might grind to a halt. And to use many of the powerful moves in
	the moves package, you need to write a lot of boilerplate methods to
	integrate correctly. Finally, you end up repeating yourself often--which
	makes it a pain if you change the name of a move.

	Take this example:

		//+autoreader
		type MoveDealInitialCards struct {
			moves.DealComponentsUntilPlayerCountReached
		}

		var moveDealInitialCardsConfig = boardgame.MoveTypeConfig {
			Name: "Deal Initial Cards",
			HelpText: "Deal initial cards to players",
			MoveConstructor: func() boardgame.Move {
				return new(MoveDealInitialCards)
			},
			IsFixUp: true,
		}

		func (m *MoveDealInitialCards) GameStack(gState boardgame.MutableSubState) boardgame.MutableStack {
			return gState.(*gameState).DrawStack
		}

		func (m *MoveDealInitialCards) PlayerStack(pState boardgame.MutablePlayerState) boardgame.MutableStack {
			return pState.(*playerState).Hand
		}

		func (m *MoveDealInitialCards) TargetCount() int {
			return 2
		}

		func (g *gameDelegate) ConfigureMoves() *boardgame.MoveTypeConfigBundle {
			return boardgame.NewMoveTypeConfigBundle().AddMoves(
				&moveDealInitialCardsConfig,
			)
		}

	auto.Config (and its panic-y sibling auto.MustConfig) help reduce this
	signficantly:

		func (g *gameDelegate) ConfigureMoves() *boardgame.MoveTypeConfigBundle {
			return boardgame.NewMoveTypeConfigBundle().AddMoves(
				auto.MustConfig(
					new(MoveDealInitialCards),
					moves.WithGameStack("DrawStack"),
					moves.WithPlayerStack("Hand"),
					moves.WithTargetCount(2),
				)
			)
		}

	Basic Usage

	auto.Config takes an example struct representing your move, and then a
	list of 0 to n interfaces.CustomConfigurationOption. These options are
	given a boardgame.PropertyCollection and then add specific properties to
	it, and then stash that on the CustomConfiguration property of the
	returned MoveTypeConfig. Different move methods will then reach into that
	configuration to alter the behavior of moves of that type. The moves
	package defines a large collection of these config options, all with names
	starting with "With".

	Moves that are used with auto.Config must satisfy the AutoConfigurableMove
	interface, which adds four methods to the normal signature:
	MoveTypeName(), MoveTypeHelpText(), MoveTypeIsFixUp(), and
	MoveTypeLegalPhases(). auto.Config primarily consistsn of some set up and
	then using those return values as fields on the returned MoveTypeConfig.
	These methods are implemented in moves.Base, which means that any move
	structs that embed moves.Base (directly or indirectly) can be used with
	auto.Config.

	moves.Base does a fair bit of magic in these methods to implement much of
	the logic of auto.Config. In general, if you pass a configuration option
	(via WithMoveName, for example) then that option will be used for that
	method. moves.Base.MoveTypeName() also will use reflection to
	automatically set a struct name like "MoveDealInitialCards" to "Deal
	Initial Cards". moves.Base's MoveType* methods will fall back on the
	move's MoveTypeFallback* methods if no other options are provided; all of
	the moves in the moves package return reasonable values for those.

	Other moves in the moves package, like DealCountComponents, will use
	configuration, like WithGameStack(), to power their default GameStack()
	method.

	Refer to the documentation of the various methods in that package for
	their precise behavior and how to configure them.

	Idiomatic Move Definition and Installation

	auto.Config is at the core of idiomatic definition and installation of
	moves, and typically is used for every move you install in your game. The
	following paragraphs describe the high-level idioms to follow.

	Never create your own MoveTypeConfig objects--it's just another global
	variable that clutters up your code and makes it harder to change.
	Instead, use auto.Config. There are some rare cases where you do want to
	refer to the move by name (and not rely on finicky string-based lookup),
	such as when you want an Agent to propose a speciifc type of move. In
	those cases use auto.Config to create the move type config, then save the
	resulting config's Name to a global variable that you use elsewhere, and
	then pass the created config to bundle.AddMoves (or its cousins).

	In general, you should only create a bespoke Move struct in your game if
	it is not possible to use one of the off-the-shelf moves from the moves
	package, combined with configuarion options, to do what you want. In
	practice this means that only if you need to override a method on one of
	the base moves do you need to create a bespoke struct. This typically
	allows you to drastically reduce the number of bespoke move structs your
	game defines, saving thousands of lines of code (each bespoke struct also
	has hundreds of lines of auto-generated PropertyReader code).

	If you do create a bespoke struct, name it like this: "MoveNameOfMyMove",
	so that moves.Base's default MoveTypeName() will give it a reasonable name
	automatically (in this example, "Name Of My Move").

	In many cases if you subclass powerful moves like DealCountComponents the
	default MoveTypeHelpText() value is sufficient (especially if it's a FixUp
	move that won't ever be seen by players). In other cases, WithHelpText()
	is often the only config option you will pass to auto.Config.

	If your move will be a FixUp move that doesn't sublcass one of the more
	advanced fix up moves (like RoundRobin or DealCountComponents), embed
	moves.FixUp into your struct. That will cause MoveTypeIsFixUp to return
	the right value even without using WithIsFixUp--because WithIsFixUp is
	easy to forget given that it's often in a different file. In almost all
	cases if you use WithIsFixUp you should simply embed moves.FixUp instead.

	auto.MustConfig is like auto.Config, but instead of returning a
	*MoveTypeConfig and an error, it simply returns a *MoveTypeConfig--and
	panics if it would have returned an error. Since your GameDelegate's
	ConfigureMoves() is typically called during the boot-up sequence of your
	game, it is safe to use auto.MustConfig exclusively, which saves many
	lines of boilerplate error checking.

*/
package auto
<commit_msg>Update documentation to make it clear that if you give bad validation to moves they will error. Part of #563.<commit_after>/*

	auto is a package designed to make it trivial to create MoveTypeConfigs
	for your moves.

	Use Case

	Creating MoveTypeConfig is a necessary part of installing moves on your
	GameManager, but it's verbose and error-prone. You need to create a lot of
	extra structs, and then remember to provide the right properties in your
	config. For example, if you forget IsFixUp: true for a fixup move, your
	game logic might grind to a halt. And to use many of the powerful moves in
	the moves package, you need to write a lot of boilerplate methods to
	integrate correctly. Finally, you end up repeating yourself often--which
	makes it a pain if you change the name of a move.

	Take this example:

		//+autoreader
		type MoveDealInitialCards struct {
			moves.DealComponentsUntilPlayerCountReached
		}

		var moveDealInitialCardsConfig = boardgame.MoveTypeConfig {
			Name: "Deal Initial Cards",
			HelpText: "Deal initial cards to players",
			MoveConstructor: func() boardgame.Move {
				return new(MoveDealInitialCards)
			},
			IsFixUp: true,
		}

		func (m *MoveDealInitialCards) GameStack(gState boardgame.MutableSubState) boardgame.MutableStack {
			return gState.(*gameState).DrawStack
		}

		func (m *MoveDealInitialCards) PlayerStack(pState boardgame.MutablePlayerState) boardgame.MutableStack {
			return pState.(*playerState).Hand
		}

		func (m *MoveDealInitialCards) TargetCount() int {
			return 2
		}

		func (g *gameDelegate) ConfigureMoves() *boardgame.MoveTypeConfigBundle {
			return boardgame.NewMoveTypeConfigBundle().AddMoves(
				&moveDealInitialCardsConfig,
			)
		}

	auto.Config (and its panic-y sibling auto.MustConfig) help reduce this
	signficantly:

		func (g *gameDelegate) ConfigureMoves() *boardgame.MoveTypeConfigBundle {
			return boardgame.NewMoveTypeConfigBundle().AddMoves(
				auto.MustConfig(
					new(MoveDealInitialCards),
					moves.WithGameStack("DrawStack"),
					moves.WithPlayerStack("Hand"),
					moves.WithTargetCount(2),
				)
			)
		}

	Basic Usage

	auto.Config takes an example struct representing your move, and then a
	list of 0 to n interfaces.CustomConfigurationOption. These options are
	given a boardgame.PropertyCollection and then add specific properties to
	it, and then stash that on the CustomConfiguration property of the
	returned MoveTypeConfig. Different move methods will then reach into that
	configuration to alter the behavior of moves of that type. The moves
	package defines a large collection of these config options, all with names
	starting with "With".

	Moves that are used with auto.Config must satisfy the AutoConfigurableMove
	interface, which adds four methods to the normal signature:
	MoveTypeName(), MoveTypeHelpText(), MoveTypeIsFixUp(), and
	MoveTypeLegalPhases(). auto.Config primarily consistsn of some set up and
	then using those return values as fields on the returned MoveTypeConfig.
	These methods are implemented in moves.Base, which means that any move
	structs that embed moves.Base (directly or indirectly) can be used with
	auto.Config.

	moves.Base does a fair bit of magic in these methods to implement much of
	the logic of auto.Config. In general, if you pass a configuration option
	(via WithMoveName, for example) then that option will be used for that
	method. moves.Base.MoveTypeName() also will use reflection to
	automatically set a struct name like "MoveDealInitialCards" to "Deal
	Initial Cards". moves.Base's MoveType* methods will fall back on the
	move's MoveTypeFallback* methods if no other options are provided; all of
	the moves in the moves package return reasonable values for those.

	Other moves in the moves package, like DealCountComponents, will use
	configuration, like WithGameStack(), to power their default GameStack()
	method.

	All moves in the moves package are designed to return an error from
	ValidConfiguration(), which means that if you forgot to pass a required
	configuration property (e.g. you don't override GameStack and also don't
	provide WithGameStack), when you try to create NewGameManager() and all
	moves' ValidConfiguration() is checked, you'll get an error. This helps
	catch mis-configurations during boot time.

	Refer to the documentation of the various methods in that package for
	their precise behavior and how to configure them.

	Idiomatic Move Definition and Installation

	auto.Config is at the core of idiomatic definition and installation of
	moves, and typically is used for every move you install in your game. The
	following paragraphs describe the high-level idioms to follow.

	Never create your own MoveTypeConfig objects--it's just another global
	variable that clutters up your code and makes it harder to change.
	Instead, use auto.Config. There are some rare cases where you do want to
	refer to the move by name (and not rely on finicky string-based lookup),
	such as when you want an Agent to propose a speciifc type of move. In
	those cases use auto.Config to create the move type config, then save the
	resulting config's Name to a global variable that you use elsewhere, and
	then pass the created config to bundle.AddMoves (or its cousins).

	In general, you should only create a bespoke Move struct in your game if
	it is not possible to use one of the off-the-shelf moves from the moves
	package, combined with configuarion options, to do what you want. In
	practice this means that only if you need to override a method on one of
	the base moves do you need to create a bespoke struct. This typically
	allows you to drastically reduce the number of bespoke move structs your
	game defines, saving thousands of lines of code (each bespoke struct also
	has hundreds of lines of auto-generated PropertyReader code).

	If you do create a bespoke struct, name it like this: "MoveNameOfMyMove",
	so that moves.Base's default MoveTypeName() will give it a reasonable name
	automatically (in this example, "Name Of My Move").

	In many cases if you subclass powerful moves like DealCountComponents the
	default MoveTypeHelpText() value is sufficient (especially if it's a FixUp
	move that won't ever be seen by players). In other cases, WithHelpText()
	is often the only config option you will pass to auto.Config.

	If your move will be a FixUp move that doesn't sublcass one of the more
	advanced fix up moves (like RoundRobin or DealCountComponents), embed
	moves.FixUp into your struct. That will cause MoveTypeIsFixUp to return
	the right value even without using WithIsFixUp--because WithIsFixUp is
	easy to forget given that it's often in a different file. In almost all
	cases if you use WithIsFixUp you should simply embed moves.FixUp instead.

	auto.MustConfig is like auto.Config, but instead of returning a
	*MoveTypeConfig and an error, it simply returns a *MoveTypeConfig--and
	panics if it would have returned an error. Since your GameDelegate's
	ConfigureMoves() is typically called during the boot-up sequence of your
	game, it is safe to use auto.MustConfig exclusively, which saves many
	lines of boilerplate error checking.

*/
package auto
<|endoftext|>


<commit_before>package msgpack

import (
	"reflect"
	"sync"
)

// Encode writes the MessagePack encoding of v to the stream.
//
// Encode traverses the value v recursively. If an encountered value implements
// the Marshaler interface Encode calls its MarshalMsgPack method to write the
// value to the stream.
//
// Otherwise, Encode uses the following type-dependent default encodings:
//
//  Go Type             MessagePack Type
//  bool                true or false
//  float32, float64    float64
//  string              string
//  []byte              binary
//  slices, arrays      array
//  struct, map         map
//
// Struct values encode as maps or arrays. If any struct field tag specifies
// the "array" option, then the struct is encoded as an array. Otherwise, the
// struct is encoded as a map.  Each exported struct field becomes a member of
// the map unless
//   - the field's tag is "-", or
//   - the field is empty and its tag specifies the "omitempty" option.
//
// Anonymous struct fields are marshaled as if their inner exported fields
// were fields in the outer struct.
//
// The struct field tag "empty" specifies a default value when decoding and the
// empty value for the "omitempty" option.
//
// Pointer values encode as the value pointed to. A nil pointer encodes as the
// MessagePack nil value.
//
// Interface values encode as the value contained in the interface. A nil
// interface value encodes as the MessagePack nil value.
func (e *Encoder) Encode(v interface{}) (err error) {
	if v == nil {
		return e.PackNil()
	}
	defer handleAbort(&err)
	rv := reflect.ValueOf(v)
	encoderForType(rv.Type(), nil)(e, rv)
	return nil
}

type encodeFunc func(e *Encoder, v reflect.Value)

type encodeBuilder struct {
	m map[reflect.Type]encodeFunc
}

var encodeFuncCache struct {
	sync.RWMutex
	m map[reflect.Type]encodeFunc
}

func encoderForType(t reflect.Type, b *encodeBuilder) encodeFunc {
	encodeFuncCache.RLock()
	f, ok := encodeFuncCache.m[t]
	encodeFuncCache.RUnlock()
	if ok {
		return f
	}

	save := false
	if b == nil {
		b = &encodeBuilder{m: make(map[reflect.Type]encodeFunc)}
		save = true
	} else if f, ok := b.m[t]; ok {
		return f
	}
	// Add temporary entry to break recursion.
	b.m[t] = func(e *Encoder, v reflect.Value) {
		f(e, v)
	}
	f = b.encoder(t)
	b.m[t] = f

	if save {
		encodeFuncCache.Lock()
		if encodeFuncCache.m == nil {
			encodeFuncCache.m = make(map[reflect.Type]encodeFunc)
		}
		for t, f := range b.m {
			encodeFuncCache.m[t] = f
		}
		encodeFuncCache.Unlock()
	}
	return f
}

func (b *encodeBuilder) encoder(t reflect.Type) encodeFunc {
	if t.Implements(marshalerType) {
		return b.marshalEncoder(t)
	}
	var f encodeFunc
	switch t.Kind() {
	case reflect.Bool:
		f = boolEncoder
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		f = intEncoder
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		f = uintEncoder
	case reflect.Float32, reflect.Float64:
		f = floatEncoder
	case reflect.String:
		f = stringEncoder
	case reflect.Array:
		f = b.arrayEncoder(t)
	case reflect.Slice:
		f = b.sliceEncoder(t)
	case reflect.Map:
		f = b.mapEncoder(t)
	case reflect.Interface:
		f = interfaceEncoder
	case reflect.Struct:
		f = b.structEncoder(t)
	case reflect.Ptr:
		f = b.ptrEncoder(t)
	default:
		f = encodeUnsupportedType
	}
	if t.Kind() != reflect.Ptr && reflect.PtrTo(t).Implements(marshalerType) {
		f = marshalAddrEncoder{f}.encode
	}
	return f
}

func nilEncoder(e *Encoder, v reflect.Value) {
	if err := e.PackNil(); err != nil {
		abort(err)
	}
}

func boolEncoder(e *Encoder, v reflect.Value) {
	if err := e.PackBool(v.Bool()); err != nil {
		abort(err)
	}
}

func intEncoder(e *Encoder, v reflect.Value) {
	if err := e.PackInt(v.Int()); err != nil {
		abort(err)
	}
}

func uintEncoder(e *Encoder, v reflect.Value) {
	if err := e.PackUint(v.Uint()); err != nil {
		abort(err)
	}
}

func floatEncoder(e *Encoder, v reflect.Value) {
	if err := e.PackFloat(v.Float()); err != nil {
		abort(err)
	}
}

func stringEncoder(e *Encoder, v reflect.Value) {
	if err := e.PackString(v.String()); err != nil {
		abort(err)
	}
}

func byteSliceEncoder(e *Encoder, v reflect.Value) {
	if err := e.PackBinary(v.Bytes()); err != nil {
		abort(err)
	}
}

func interfaceEncoder(e *Encoder, v reflect.Value) {
	if !v.IsValid() || v.IsNil() {
		nilEncoder(e, v)
		return
	}
	v = v.Elem()
	encoderForType(v.Type(), nil)(e, v)
}

type ptrEncoder struct{ elem encodeFunc }

func (enc ptrEncoder) encode(e *Encoder, v reflect.Value) {
	if v.IsNil() {
		nilEncoder(e, v)
		return
	}
	enc.elem(e, v.Elem())
}

func (b *encodeBuilder) ptrEncoder(t reflect.Type) encodeFunc {
	return ptrEncoder{encoderForType(t.Elem(), b)}.encode
}

type mapEncoder struct{ key, elem encodeFunc }

func (enc *mapEncoder) encode(e *Encoder, v reflect.Value) {
	if v.IsNil() {
		nilEncoder(e, v)
		return
	}
	if err := e.PackMapLen(int64(v.Len())); err != nil {
		abort(err)
	}
	for _, k := range v.MapKeys() {
		enc.key(e, k)
		enc.elem(e, v.MapIndex(k))
	}
}

func (b *encodeBuilder) mapEncoder(t reflect.Type) encodeFunc {
	enc := &mapEncoder{key: encoderForType(t.Key(), b), elem: encoderForType(t.Elem(), b)}
	return enc.encode
}

type sliceArrayEncoder struct{ elem encodeFunc }

func (enc sliceArrayEncoder) encodeArray(e *Encoder, v reflect.Value) {
	if err := e.PackArrayLen(int64(v.Len())); err != nil {
		abort(err)
	}
	for i := 0; i < v.Len(); i++ {
		enc.elem(e, v.Index(i))
	}
}

func (b *encodeBuilder) arrayEncoder(t reflect.Type) encodeFunc {
	return sliceArrayEncoder{encoderForType(t.Elem(), b)}.encodeArray
}

func (enc sliceArrayEncoder) encodeSlice(e *Encoder, v reflect.Value) {
	if v.IsNil() {
		nilEncoder(e, v)
		return
	}
	enc.encodeArray(e, v)
}

func (b *encodeBuilder) sliceEncoder(t reflect.Type) encodeFunc {
	if t.Elem().Kind() == reflect.Uint8 {
		return byteSliceEncoder
	}
	return sliceArrayEncoder{encoderForType(t.Elem(), b)}.encodeSlice
}

// Marshaler is the interface implemented by objects that can encode themselves
// to a MessagePack stream.
type Marshaler interface {
	MarshalMsgPack(e *Encoder) error
}

var marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()

func marshalPtrEncoder(e *Encoder, v reflect.Value) {
	if v.IsNil() {
		nilEncoder(e, v)
		return
	}
	marshalEncoder(e, v)
}

func marshalEncoder(e *Encoder, v reflect.Value) {
	m := v.Interface().(Marshaler)
	if err := m.MarshalMsgPack(e); err != nil {
		abort(err)
	}
}

func (b *encodeBuilder) marshalEncoder(t reflect.Type) encodeFunc {
	if t.Kind() == reflect.Ptr {
		return marshalPtrEncoder
	}
	return marshalEncoder
}

type marshalAddrEncoder struct{ f encodeFunc }

func (enc marshalAddrEncoder) encode(e *Encoder, v reflect.Value) {
	if v.CanAddr() {
		marshalEncoder(e, v.Addr())
		return
	}
	enc.f(e, v)
}

type fieldEnc struct {
	name  string
	empty func(reflect.Value) bool
	f     encodeFunc
	index []int
}

type structEncoder []*fieldEnc

func (enc structEncoder) encode(e *Encoder, v reflect.Value) {
	var n int64
	for _, fe := range enc {
		fv := fieldByIndex(v, fe.index)
		if !fv.IsValid() || (fe.empty != nil && fe.empty(fv)) {
			continue
		}
		n++
	}
	if err := e.PackMapLen(n); err != nil {
		abort(err)
	}
	for _, fe := range enc {
		fv := fieldByIndex(v, fe.index)
		if !fv.IsValid() || (fe.empty != nil && fe.empty(fv)) {
			continue
		}
		if err := e.PackString(fe.name); err != nil {
			abort(err)
		}
		fe.f(e, fv)
	}
}

func (enc structEncoder) encodeArray(e *Encoder, v reflect.Value) {
	if err := e.PackArrayLen(int64(len(enc))); err != nil {
		abort(err)
	}
	for _, fe := range enc {
		fv := fieldByIndex(v, fe.index)
		fe.f(e, fv)
	}
}

func (b *encodeBuilder) structEncoder(t reflect.Type) encodeFunc {
	fields, array := fieldsForType(t)
	enc := make(structEncoder, len(fields))
	for i, f := range fields {
		var empty func(reflect.Value) bool
		if f.omitEmpty {
			empty = emptyFunc(f)
		}
		enc[i] = &fieldEnc{
			name:  f.name,
			empty: empty,
			index: f.index,
			f:     encoderForType(f.typ, b)}
	}
	if array {
		return enc.encodeArray
	}
	return enc.encode
}

func emptyFunc(f *field) func(reflect.Value) bool {
	if f.empty.IsValid() {
		return func(v reflect.Value) bool { return v.Interface() == f.empty.Interface() }
	}
	switch f.typ.Kind() {
	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		return lenEmpty
	case reflect.Bool:
		return boolEmpty
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return intEmpty
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return uintEmpty
	case reflect.Float32, reflect.Float64:
		return floatEmpty
	case reflect.Interface, reflect.Ptr:
		return nilEmpty
	default:
		return nil
	}
}

func intEmpty(v reflect.Value) bool   { return v.Int() == 0 }
func uintEmpty(v reflect.Value) bool  { return v.Uint() == 0 }
func floatEmpty(v reflect.Value) bool { return v.Float() == 0 }
func boolEmpty(v reflect.Value) bool  { return !v.Bool() }
func lenEmpty(v reflect.Value) bool   { return v.Len() == 0 }
func nilEmpty(v reflect.Value) bool   { return v.IsNil() }

type encodeTypeError struct {
	Type reflect.Type
}

func (e *encodeTypeError) Error() string {
	return "msgpack: unsupported type: " + e.Type.String()
}

func encodeUnsupportedType(e *Encoder, v reflect.Value) {
	abort(&encodeTypeError{v.Type()})
}
<commit_msg>msgpack: move Marshaler type to top of encode.go<commit_after>package msgpack

import (
	"reflect"
	"sync"
)

// Marshaler is the interface implemented by objects that can encode themselves
// to a MessagePack stream.
type Marshaler interface {
	MarshalMsgPack(e *Encoder) error
}

// Encode writes the MessagePack encoding of v to the stream.
//
// Encode traverses the value v recursively. If an encountered value implements
// the Marshaler interface Encode calls its MarshalMsgPack method to write the
// value to the stream.
//
// Otherwise, Encode uses the following type-dependent default encodings:
//
//  Go Type             MessagePack Type
//  bool                true or false
//  float32, float64    float64
//  string              string
//  []byte              binary
//  slices, arrays      array
//  struct, map         map
//
// Struct values encode as maps or arrays. If any struct field tag specifies
// the "array" option, then the struct is encoded as an array. Otherwise, the
// struct is encoded as a map.  Each exported struct field becomes a member of
// the map unless
//   - the field's tag is "-", or
//   - the field is empty and its tag specifies the "omitempty" option.
//
// Anonymous struct fields are marshaled as if their inner exported fields
// were fields in the outer struct.
//
// The struct field tag "empty" specifies a default value when decoding and the
// empty value for the "omitempty" option.
//
// Pointer values encode as the value pointed to. A nil pointer encodes as the
// MessagePack nil value.
//
// Interface values encode as the value contained in the interface. A nil
// interface value encodes as the MessagePack nil value.
func (e *Encoder) Encode(v interface{}) (err error) {
	if v == nil {
		return e.PackNil()
	}
	defer handleAbort(&err)
	rv := reflect.ValueOf(v)
	encoderForType(rv.Type(), nil)(e, rv)
	return nil
}

type encodeFunc func(e *Encoder, v reflect.Value)

type encodeBuilder struct {
	m map[reflect.Type]encodeFunc
}

var encodeFuncCache struct {
	sync.RWMutex
	m map[reflect.Type]encodeFunc
}

func encoderForType(t reflect.Type, b *encodeBuilder) encodeFunc {
	encodeFuncCache.RLock()
	f, ok := encodeFuncCache.m[t]
	encodeFuncCache.RUnlock()
	if ok {
		return f
	}

	save := false
	if b == nil {
		b = &encodeBuilder{m: make(map[reflect.Type]encodeFunc)}
		save = true
	} else if f, ok := b.m[t]; ok {
		return f
	}
	// Add temporary entry to break recursion.
	b.m[t] = func(e *Encoder, v reflect.Value) {
		f(e, v)
	}
	f = b.encoder(t)
	b.m[t] = f

	if save {
		encodeFuncCache.Lock()
		if encodeFuncCache.m == nil {
			encodeFuncCache.m = make(map[reflect.Type]encodeFunc)
		}
		for t, f := range b.m {
			encodeFuncCache.m[t] = f
		}
		encodeFuncCache.Unlock()
	}
	return f
}

func (b *encodeBuilder) encoder(t reflect.Type) encodeFunc {
	if t.Implements(marshalerType) {
		return b.marshalEncoder(t)
	}
	var f encodeFunc
	switch t.Kind() {
	case reflect.Bool:
		f = boolEncoder
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		f = intEncoder
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		f = uintEncoder
	case reflect.Float32, reflect.Float64:
		f = floatEncoder
	case reflect.String:
		f = stringEncoder
	case reflect.Array:
		f = b.arrayEncoder(t)
	case reflect.Slice:
		f = b.sliceEncoder(t)
	case reflect.Map:
		f = b.mapEncoder(t)
	case reflect.Interface:
		f = interfaceEncoder
	case reflect.Struct:
		f = b.structEncoder(t)
	case reflect.Ptr:
		f = b.ptrEncoder(t)
	default:
		f = encodeUnsupportedType
	}
	if t.Kind() != reflect.Ptr && reflect.PtrTo(t).Implements(marshalerType) {
		f = marshalAddrEncoder{f}.encode
	}
	return f
}

func nilEncoder(e *Encoder, v reflect.Value) {
	if err := e.PackNil(); err != nil {
		abort(err)
	}
}

func boolEncoder(e *Encoder, v reflect.Value) {
	if err := e.PackBool(v.Bool()); err != nil {
		abort(err)
	}
}

func intEncoder(e *Encoder, v reflect.Value) {
	if err := e.PackInt(v.Int()); err != nil {
		abort(err)
	}
}

func uintEncoder(e *Encoder, v reflect.Value) {
	if err := e.PackUint(v.Uint()); err != nil {
		abort(err)
	}
}

func floatEncoder(e *Encoder, v reflect.Value) {
	if err := e.PackFloat(v.Float()); err != nil {
		abort(err)
	}
}

func stringEncoder(e *Encoder, v reflect.Value) {
	if err := e.PackString(v.String()); err != nil {
		abort(err)
	}
}

func byteSliceEncoder(e *Encoder, v reflect.Value) {
	if err := e.PackBinary(v.Bytes()); err != nil {
		abort(err)
	}
}

func interfaceEncoder(e *Encoder, v reflect.Value) {
	if !v.IsValid() || v.IsNil() {
		nilEncoder(e, v)
		return
	}
	v = v.Elem()
	encoderForType(v.Type(), nil)(e, v)
}

type ptrEncoder struct{ elem encodeFunc }

func (enc ptrEncoder) encode(e *Encoder, v reflect.Value) {
	if v.IsNil() {
		nilEncoder(e, v)
		return
	}
	enc.elem(e, v.Elem())
}

func (b *encodeBuilder) ptrEncoder(t reflect.Type) encodeFunc {
	return ptrEncoder{encoderForType(t.Elem(), b)}.encode
}

type mapEncoder struct{ key, elem encodeFunc }

func (enc *mapEncoder) encode(e *Encoder, v reflect.Value) {
	if v.IsNil() {
		nilEncoder(e, v)
		return
	}
	if err := e.PackMapLen(int64(v.Len())); err != nil {
		abort(err)
	}
	for _, k := range v.MapKeys() {
		enc.key(e, k)
		enc.elem(e, v.MapIndex(k))
	}
}

func (b *encodeBuilder) mapEncoder(t reflect.Type) encodeFunc {
	enc := &mapEncoder{key: encoderForType(t.Key(), b), elem: encoderForType(t.Elem(), b)}
	return enc.encode
}

type sliceArrayEncoder struct{ elem encodeFunc }

func (enc sliceArrayEncoder) encodeArray(e *Encoder, v reflect.Value) {
	if err := e.PackArrayLen(int64(v.Len())); err != nil {
		abort(err)
	}
	for i := 0; i < v.Len(); i++ {
		enc.elem(e, v.Index(i))
	}
}

func (b *encodeBuilder) arrayEncoder(t reflect.Type) encodeFunc {
	return sliceArrayEncoder{encoderForType(t.Elem(), b)}.encodeArray
}

func (enc sliceArrayEncoder) encodeSlice(e *Encoder, v reflect.Value) {
	if v.IsNil() {
		nilEncoder(e, v)
		return
	}
	enc.encodeArray(e, v)
}

func (b *encodeBuilder) sliceEncoder(t reflect.Type) encodeFunc {
	if t.Elem().Kind() == reflect.Uint8 {
		return byteSliceEncoder
	}
	return sliceArrayEncoder{encoderForType(t.Elem(), b)}.encodeSlice
}

var marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()

func marshalPtrEncoder(e *Encoder, v reflect.Value) {
	if v.IsNil() {
		nilEncoder(e, v)
		return
	}
	marshalEncoder(e, v)
}

func marshalEncoder(e *Encoder, v reflect.Value) {
	m := v.Interface().(Marshaler)
	if err := m.MarshalMsgPack(e); err != nil {
		abort(err)
	}
}

func (b *encodeBuilder) marshalEncoder(t reflect.Type) encodeFunc {
	if t.Kind() == reflect.Ptr {
		return marshalPtrEncoder
	}
	return marshalEncoder
}

type marshalAddrEncoder struct{ f encodeFunc }

func (enc marshalAddrEncoder) encode(e *Encoder, v reflect.Value) {
	if v.CanAddr() {
		marshalEncoder(e, v.Addr())
		return
	}
	enc.f(e, v)
}

type fieldEnc struct {
	name  string
	empty func(reflect.Value) bool
	f     encodeFunc
	index []int
}

type structEncoder []*fieldEnc

func (enc structEncoder) encode(e *Encoder, v reflect.Value) {
	var n int64
	for _, fe := range enc {
		fv := fieldByIndex(v, fe.index)
		if !fv.IsValid() || (fe.empty != nil && fe.empty(fv)) {
			continue
		}
		n++
	}
	if err := e.PackMapLen(n); err != nil {
		abort(err)
	}
	for _, fe := range enc {
		fv := fieldByIndex(v, fe.index)
		if !fv.IsValid() || (fe.empty != nil && fe.empty(fv)) {
			continue
		}
		if err := e.PackString(fe.name); err != nil {
			abort(err)
		}
		fe.f(e, fv)
	}
}

func (enc structEncoder) encodeArray(e *Encoder, v reflect.Value) {
	if err := e.PackArrayLen(int64(len(enc))); err != nil {
		abort(err)
	}
	for _, fe := range enc {
		fv := fieldByIndex(v, fe.index)
		fe.f(e, fv)
	}
}

func (b *encodeBuilder) structEncoder(t reflect.Type) encodeFunc {
	fields, array := fieldsForType(t)
	enc := make(structEncoder, len(fields))
	for i, f := range fields {
		var empty func(reflect.Value) bool
		if f.omitEmpty {
			empty = emptyFunc(f)
		}
		enc[i] = &fieldEnc{
			name:  f.name,
			empty: empty,
			index: f.index,
			f:     encoderForType(f.typ, b)}
	}
	if array {
		return enc.encodeArray
	}
	return enc.encode
}

func emptyFunc(f *field) func(reflect.Value) bool {
	if f.empty.IsValid() {
		return func(v reflect.Value) bool { return v.Interface() == f.empty.Interface() }
	}
	switch f.typ.Kind() {
	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		return lenEmpty
	case reflect.Bool:
		return boolEmpty
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return intEmpty
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return uintEmpty
	case reflect.Float32, reflect.Float64:
		return floatEmpty
	case reflect.Interface, reflect.Ptr:
		return nilEmpty
	default:
		return nil
	}
}

func intEmpty(v reflect.Value) bool   { return v.Int() == 0 }
func uintEmpty(v reflect.Value) bool  { return v.Uint() == 0 }
func floatEmpty(v reflect.Value) bool { return v.Float() == 0 }
func boolEmpty(v reflect.Value) bool  { return !v.Bool() }
func lenEmpty(v reflect.Value) bool   { return v.Len() == 0 }
func nilEmpty(v reflect.Value) bool   { return v.IsNil() }

type encodeTypeError struct {
	Type reflect.Type
}

func (e *encodeTypeError) Error() string {
	return "msgpack: unsupported type: " + e.Type.String()
}

func encodeUnsupportedType(e *Encoder, v reflect.Value) {
	abort(&encodeTypeError{v.Type()})
}
<|endoftext|>


<commit_before>/*
 * gomacro - A Go interpreter with Lisp-like macros
 *
 * Copyright (C) 2017-2018 Massimiliano Ghilardi
 *
 *     This Source Code Form is subject to the terms of the Mozilla Public
 *     License, v. 2.0. If a copy of the MPL was not distributed with this
 *     file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *
 * lookup.go
 *
 *  Created on May 07, 2017
 *      Author Massimiliano Ghilardi
 */

package xreflect

import (
	"go/types"
	"reflect"

	"github.com/cosmos72/gomacro/typeutil"
)

type depthMap struct {
	gmap typeutil.Map
}

func (m *depthMap) visited(gtype types.Type, depth int) bool {
	if at := m.gmap.At(gtype); at != nil && at.(int) < depth {
		// already visited at shallower depth.
		// avoids infinite loop for self-referencing types
		// as type X struct { *X }
		return true
	}
	m.gmap.Set(gtype, depth)
	return false
}

// FieldByName returns the (possibly embedded) struct field with given name,
// and the number of fields found at the same (shallowest) depth: 0 if not found.
// Private fields are returned only if they were declared in pkgpath.
func (t *xtype) FieldByName(name, pkgpath string) (field StructField, count int) {
	if name == "_" || t.kind != reflect.Struct {
		return
	}
	// debugf("field cache for %v <%v> = %v", unsafe.Pointer(t), t, t.fieldcache)
	qname := QName2(name, pkgpath)

	v := t.universe
	if v.ThreadSafe {
		defer un(lock(v))
	}
	field, found := t.fieldcache[qname]
	if found {
		if field.Index == nil { // marker for ambiguous field names
			count = int(field.Offset) // reuse Offset as "number of ambiguous fields"
		} else {
			count = 1
		}
		return field, count
	}
	var tovisit []StructField
	var visited depthMap
	field, count, tovisit = fieldByName(t, qname, 0, nil, &visited)

	// breadth-first recursion
	for count == 0 && len(tovisit) != 0 {
		var next []StructField
		for _, f := range tovisit {
			efield, ecount, etovisit := fieldByName(unwrap(f.Type), qname, f.Offset, f.Index, &visited)
			if count == 0 {
				if ecount > 0 {
					field = efield
				} else {
					// no recursion if we found something
					next = append(next, etovisit...)
				}
			}
			count += ecount
		}
		tovisit = next
	}
	if count > 0 {
		cacheFieldByName(t, qname, &field, count)
	}
	return field, count
}

func fieldByName(t *xtype, qname QName, offset uintptr, index []int, m *depthMap) (field StructField, count int, tovisit []StructField) {
	// also support embedded fields: they can be named types or pointers to named types
	t, gtype := derefStruct(t)
	if gtype == nil || m.visited(gtype, len(index)) {
		return
	}
	// debugf("fieldByName: visiting %v <%v> <%v> at depth %d", t.kind, t.gtype, t.rtype, len(index))

	n := t.NumField()
	for i := 0; i < n; i++ {

		gfield := gtype.Field(i)
		if matchFieldByName(qname, gfield) {
			if count == 0 {
				field = t.field(i) // lock already held. makes a copy
				field.Offset += offset
				field.Index = concat(index, field.Index) // make a copy of index
				// debugf("fieldByName: %d-th field of <%v> matches: %#v", i, t.rtype, field)
			}
			count++
		} else if count == 0 && gfield.Anonymous() {
			efield := t.field(i) // lock already held
			efield.Offset += offset
			efield.Index = concat(index, efield.Index) // make a copy of index
			// debugf("fieldByName: %d-th field of <%v> is anonymous: %#v", i, t.rtype, efield)
			tovisit = append(tovisit, efield)
		}
	}
	return field, count, tovisit
}

func derefStruct(t *xtype) (*xtype, *types.Struct) {
	switch gtype := t.gtype.Underlying().(type) {
	case *types.Struct:
		return t, gtype
	case *types.Pointer:
		gelem, ok := gtype.Elem().Underlying().(*types.Struct)
		if ok {
			// not t.Elem(), it would acquire Universe lock
			return unwrap(t.elem()), gelem
		}
	}
	return nil, nil
}

// return true if gfield name matches given name, or if it's anonymous and its *type* name matches given name
func matchFieldByName(qname QName, gfield *types.Var) bool {
	// always check the field's package, not the type's package
	if qname == QNameGo(gfield) {
		return true
	}
	if gfield.Anonymous() {
		gtype := gfield.Type()
		if gptr, ok := gtype.(*types.Pointer); ok {
			// unnamed field has unnamed pointer type, as for example *Foo
			// check the element type
			gtype = gptr.Elem()
		}
		switch gtype := gtype.(type) {
		case *types.Basic:
			// is it possible to embed basic types?
			// yes, and they work as unexported embedded fields,
			// i.e. in the same package as the struct that includes them
			return qname == QNameGo2(gtype.Name(), gfield.Pkg())
		case *types.Named:
			// gtype.Obj().Pkg() and gfield.Pkg() should be identical for *unexported* fields
			// (they are ignored for exported fields)
			return qname == QNameGo2(gtype.Obj().Name(), gfield.Pkg())
		}
	}
	return false
}

// add field to type's fieldcache. used by Type.FieldByName after a successful lookup
func cacheFieldByName(t *xtype, qname QName, field *StructField, count int) {
	if t.fieldcache == nil {
		t.fieldcache = make(map[QName]StructField)
	}
	if count > 1 {
		field.Index = nil             // marker for ambiguous field names
		field.Offset = uintptr(count) // reuse Offset as "number of ambiguous fields"
	}
	t.fieldcache[qname] = *field
	t.universe.fieldcache = true
}

// anonymousFields returns the anonymous fields of a struct type (either named or unnamed)
// also accepts a pointer to a struct type
func anonymousFields(t *xtype, offset uintptr, index []int, m *depthMap) []StructField {
	t, gtype := derefStruct(t)
	if gtype == nil || m.visited(gtype, len(index)) {
		return nil
	}
	n := gtype.NumFields()
	var tovisit []StructField
	for i := 0; i < n; i++ {
		gfield := gtype.Field(i)
		if gfield.Anonymous() {
			field := t.field(i) // not t.Field(), it would acquire Universe lock
			field.Offset += offset
			field.Index = concat(index, field.Index) // make a copy of index
			tovisit = append(tovisit, field)
		}
	}
	return tovisit
}

// MethodByName returns the method with given name (including wrapper methods for embedded fields)
// and the number of methods found at the same (shallowest) depth: 0 if not found.
// Private methods are returned only if they were declared in pkgpath.
func (t *xtype) MethodByName(name, pkgpath string) (method Method, count int) {
	// debugf("method cache for %v <%v> = %v", unsafe.Pointer(t), t, t.methodcache)

	// only named types and interfaces can have methods
	if name == "_" || (!t.Named() && t.kind != reflect.Interface) {
		return
	}
	v := t.universe
	if v.ThreadSafe {
		defer un(lock(v))
	}
	return t.methodByName(name, pkgpath)
}

func (t *xtype) methodByName(name, pkgpath string) (method Method, count int) {
	if name == "_" || (!t.Named() && t.kind != reflect.Interface) {
		return
	}
	qname := QName2(name, pkgpath)
	method, found := t.methodcache[qname]
	if found {
		index := method.Index
		if index < 0 { // marker for ambiguous method names
			count = -index
		} else {
			count = 1
		}
		return method, count
	}
	var visited depthMap
	method, count = methodByName(t, qname, nil)
	if count == 0 {
		tovisit := anonymousFields(t, 0, nil, &visited)
		// breadth-first recursion on struct's anonymous fields
		for count == 0 && len(tovisit) != 0 {
			var next []StructField
			for _, f := range tovisit {
				et := unwrap(f.Type)
				emethod, ecount := methodByName(et, qname, f.Index)
				if count == 0 {
					if ecount > 0 {
						method = emethod
					} else {
						// no recursion if we found something
						next = append(next, anonymousFields(et, f.Offset, f.Index, &visited)...)
					}
				}
				count += ecount
			}
			tovisit = next
		}
	}
	if count > 0 {
		cacheMethodByName(t, qname, &method, count)
	}
	return method, count
}

// For interfaces, search in *all* methods including wrapper methods for embedded interfaces
// For all other named types, only search in explicitly declared methods, ignoring wrapper methods for embedded fields.
func methodByName(t *xtype, qname QName, index []int) (method Method, count int) {

	// debugf("methodByName: visiting %v <%v> <%v> at depth %d", t.kind, t.gtype, t.rtype, len(index))

	// also support embedded fields: they can be interfaces, named types, pointers to named types
	if t.kind == reflect.Ptr {
		te := unwrap(t.elem())
		if te.kind == reflect.Interface || te.kind == reflect.Ptr {
			return
		}
		t = te
	}
	n := t.NumMethod()
	for i := 0; i < n; i++ {
		gmethod := t.gmethod(i)
		if matchMethodByName(qname, gmethod) {
			if count == 0 {
				method = t.method(i)                                 // lock already held
				method.FieldIndex = concat(index, method.FieldIndex) // make a copy of index
				// debugf("methodByName: %d-th explicit method of <%v> matches: %#v", i, t.rtype, method)
			}
			count++
		}
	}
	return
}

// return true if gmethod name matches given name
func matchMethodByName(qname QName, gmethod *types.Func) bool {
	// always check the methods's package, not the type's package
	return qname == QNameGo(gmethod)
}

// add method to type's methodcache. used by Type.MethodByName after a successful lookup
func cacheMethodByName(t *xtype, qname QName, method *Method, count int) {
	if t.methodcache == nil {
		t.methodcache = make(map[QName]Method)
	}
	if count > 1 {
		method.Index = -count // marker for ambiguous method names
	}
	t.methodcache[qname] = *method
	t.universe.methodcache = true
}

// visit type's direct and embedded fields in breadth-first order
func (v *Universe) VisitFields(t Type, visitor func(StructField)) {
	xt := unwrap(t)
	if xt == nil {
		return
	}
	var curr, tovisit []*xtype
	curr = []*xtype{xt}
	var seen typeutil.Map

	for len(curr) != 0 {
		for _, xt := range curr {
			if xt == nil {
				continue
			}
			// embedded fields can be named types or pointers to named types
			xt, _ = derefStruct(xt)
			if xt.kind != reflect.Struct || seen.At(xt.gtype) != nil {
				continue
			}
			seen.Set(xt.gtype, xt.gtype)

			for i, n := 0, xt.NumField(); i < n; i++ {
				field := xt.field(i)
				visitor(field)
				if field.Anonymous {
					tovisit = append(tovisit, unwrap(field.Type))
				}
			}
		}
		curr = tovisit
		tovisit = nil
	}
}

func invalidateCache(gtype types.Type, t interface{}) {
	if t, ok := t.(Type); ok {
		t := unwrap(t)
		t.fieldcache = nil
		t.methodcache = nil
	}
}

func invalidateMethodCache(gtype types.Type, t interface{}) {
	if t, ok := t.(Type); ok {
		t := unwrap(t)
		t.methodcache = nil
	}
}

// clears all xtype.fieldcache and xtype.methodcache.
// invoked by NamedOf() when a type is redefined.
func (v *Universe) InvalidateCache() {
	if v.fieldcache || v.methodcache {
		v.gmap.Iterate(invalidateCache)
		v.fieldcache = false
		v.methodcache = false
	}
}

// clears all xtype.methodcache.
// invoked by AddMethod() when a method is redefined.
func (v *Universe) InvalidateMethodCache() {
	if v.methodcache {
		v.gmap.Iterate(invalidateMethodCache)
		v.methodcache = false
	}
}
<commit_msg>fix nil pointer dereference on TAB completion, for example reflect.Value.<TAB><commit_after>/*
 * gomacro - A Go interpreter with Lisp-like macros
 *
 * Copyright (C) 2017-2018 Massimiliano Ghilardi
 *
 *     This Source Code Form is subject to the terms of the Mozilla Public
 *     License, v. 2.0. If a copy of the MPL was not distributed with this
 *     file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *
 * lookup.go
 *
 *  Created on May 07, 2017
 *      Author Massimiliano Ghilardi
 */

package xreflect

import (
	"go/types"
	"reflect"

	"github.com/cosmos72/gomacro/typeutil"
)

type depthMap struct {
	gmap typeutil.Map
}

func (m *depthMap) visited(gtype types.Type, depth int) bool {
	if at := m.gmap.At(gtype); at != nil && at.(int) < depth {
		// already visited at shallower depth.
		// avoids infinite loop for self-referencing types
		// as type X struct { *X }
		return true
	}
	m.gmap.Set(gtype, depth)
	return false
}

// FieldByName returns the (possibly embedded) struct field with given name,
// and the number of fields found at the same (shallowest) depth: 0 if not found.
// Private fields are returned only if they were declared in pkgpath.
func (t *xtype) FieldByName(name, pkgpath string) (field StructField, count int) {
	if name == "_" || t.kind != reflect.Struct {
		return
	}
	// debugf("field cache for %v <%v> = %v", unsafe.Pointer(t), t, t.fieldcache)
	qname := QName2(name, pkgpath)

	v := t.universe
	if v.ThreadSafe {
		defer un(lock(v))
	}
	field, found := t.fieldcache[qname]
	if found {
		if field.Index == nil { // marker for ambiguous field names
			count = int(field.Offset) // reuse Offset as "number of ambiguous fields"
		} else {
			count = 1
		}
		return field, count
	}
	var tovisit []StructField
	var visited depthMap
	field, count, tovisit = fieldByName(t, qname, 0, nil, &visited)

	// breadth-first recursion
	for count == 0 && len(tovisit) != 0 {
		var next []StructField
		for _, f := range tovisit {
			efield, ecount, etovisit := fieldByName(unwrap(f.Type), qname, f.Offset, f.Index, &visited)
			if count == 0 {
				if ecount > 0 {
					field = efield
				} else {
					// no recursion if we found something
					next = append(next, etovisit...)
				}
			}
			count += ecount
		}
		tovisit = next
	}
	if count > 0 {
		cacheFieldByName(t, qname, &field, count)
	}
	return field, count
}

func fieldByName(t *xtype, qname QName, offset uintptr, index []int, m *depthMap) (field StructField, count int, tovisit []StructField) {
	// also support embedded fields: they can be named types or pointers to named types
	t, gtype := derefStruct(t)
	if gtype == nil || m.visited(gtype, len(index)) {
		return
	}
	// debugf("fieldByName: visiting %v <%v> <%v> at depth %d", t.kind, t.gtype, t.rtype, len(index))

	n := t.NumField()
	for i := 0; i < n; i++ {

		gfield := gtype.Field(i)
		if matchFieldByName(qname, gfield) {
			if count == 0 {
				field = t.field(i) // lock already held. makes a copy
				field.Offset += offset
				field.Index = concat(index, field.Index) // make a copy of index
				// debugf("fieldByName: %d-th field of <%v> matches: %#v", i, t.rtype, field)
			}
			count++
		} else if count == 0 && gfield.Anonymous() {
			efield := t.field(i) // lock already held
			efield.Offset += offset
			efield.Index = concat(index, efield.Index) // make a copy of index
			// debugf("fieldByName: %d-th field of <%v> is anonymous: %#v", i, t.rtype, efield)
			tovisit = append(tovisit, efield)
		}
	}
	return field, count, tovisit
}

func derefStruct(t *xtype) (*xtype, *types.Struct) {
	if t != nil {
		switch gtype := t.gtype.Underlying().(type) {
		case *types.Struct:
			return t, gtype
		case *types.Pointer:
			gelem, ok := gtype.Elem().Underlying().(*types.Struct)
			if ok {
				// not t.Elem(), it would acquire Universe lock
				return unwrap(t.elem()), gelem
			}
		}
	}
	return nil, nil
}

// return true if gfield name matches given name, or if it's anonymous and its *type* name matches given name
func matchFieldByName(qname QName, gfield *types.Var) bool {
	// always check the field's package, not the type's package
	if qname == QNameGo(gfield) {
		return true
	}
	if gfield.Anonymous() {
		gtype := gfield.Type()
		if gptr, ok := gtype.(*types.Pointer); ok {
			// unnamed field has unnamed pointer type, as for example *Foo
			// check the element type
			gtype = gptr.Elem()
		}
		switch gtype := gtype.(type) {
		case *types.Basic:
			// is it possible to embed basic types?
			// yes, and they work as unexported embedded fields,
			// i.e. in the same package as the struct that includes them
			return qname == QNameGo2(gtype.Name(), gfield.Pkg())
		case *types.Named:
			// gtype.Obj().Pkg() and gfield.Pkg() should be identical for *unexported* fields
			// (they are ignored for exported fields)
			return qname == QNameGo2(gtype.Obj().Name(), gfield.Pkg())
		}
	}
	return false
}

// add field to type's fieldcache. used by Type.FieldByName after a successful lookup
func cacheFieldByName(t *xtype, qname QName, field *StructField, count int) {
	if t.fieldcache == nil {
		t.fieldcache = make(map[QName]StructField)
	}
	if count > 1 {
		field.Index = nil             // marker for ambiguous field names
		field.Offset = uintptr(count) // reuse Offset as "number of ambiguous fields"
	}
	t.fieldcache[qname] = *field
	t.universe.fieldcache = true
}

// anonymousFields returns the anonymous fields of a struct type (either named or unnamed)
// also accepts a pointer to a struct type
func anonymousFields(t *xtype, offset uintptr, index []int, m *depthMap) []StructField {
	t, gtype := derefStruct(t)
	if gtype == nil || m.visited(gtype, len(index)) {
		return nil
	}
	n := gtype.NumFields()
	var tovisit []StructField
	for i := 0; i < n; i++ {
		gfield := gtype.Field(i)
		if gfield.Anonymous() {
			field := t.field(i) // not t.Field(), it would acquire Universe lock
			field.Offset += offset
			field.Index = concat(index, field.Index) // make a copy of index
			tovisit = append(tovisit, field)
		}
	}
	return tovisit
}

// MethodByName returns the method with given name (including wrapper methods for embedded fields)
// and the number of methods found at the same (shallowest) depth: 0 if not found.
// Private methods are returned only if they were declared in pkgpath.
func (t *xtype) MethodByName(name, pkgpath string) (method Method, count int) {
	// debugf("method cache for %v <%v> = %v", unsafe.Pointer(t), t, t.methodcache)

	// only named types and interfaces can have methods
	if name == "_" || (!t.Named() && t.kind != reflect.Interface) {
		return
	}
	v := t.universe
	if v.ThreadSafe {
		defer un(lock(v))
	}
	return t.methodByName(name, pkgpath)
}

func (t *xtype) methodByName(name, pkgpath string) (method Method, count int) {
	if name == "_" || (!t.Named() && t.kind != reflect.Interface) {
		return
	}
	qname := QName2(name, pkgpath)
	method, found := t.methodcache[qname]
	if found {
		index := method.Index
		if index < 0 { // marker for ambiguous method names
			count = -index
		} else {
			count = 1
		}
		return method, count
	}
	var visited depthMap
	method, count = methodByName(t, qname, nil)
	if count == 0 {
		tovisit := anonymousFields(t, 0, nil, &visited)
		// breadth-first recursion on struct's anonymous fields
		for count == 0 && len(tovisit) != 0 {
			var next []StructField
			for _, f := range tovisit {
				et := unwrap(f.Type)
				emethod, ecount := methodByName(et, qname, f.Index)
				if count == 0 {
					if ecount > 0 {
						method = emethod
					} else {
						// no recursion if we found something
						next = append(next, anonymousFields(et, f.Offset, f.Index, &visited)...)
					}
				}
				count += ecount
			}
			tovisit = next
		}
	}
	if count > 0 {
		cacheMethodByName(t, qname, &method, count)
	}
	return method, count
}

// For interfaces, search in *all* methods including wrapper methods for embedded interfaces
// For all other named types, only search in explicitly declared methods, ignoring wrapper methods for embedded fields.
func methodByName(t *xtype, qname QName, index []int) (method Method, count int) {

	// debugf("methodByName: visiting %v <%v> <%v> at depth %d", t.kind, t.gtype, t.rtype, len(index))

	// also support embedded fields: they can be interfaces, named types, pointers to named types
	if t.kind == reflect.Ptr {
		te := unwrap(t.elem())
		if te.kind == reflect.Interface || te.kind == reflect.Ptr {
			return
		}
		t = te
	}
	n := t.NumMethod()
	for i := 0; i < n; i++ {
		gmethod := t.gmethod(i)
		if matchMethodByName(qname, gmethod) {
			if count == 0 {
				method = t.method(i)                                 // lock already held
				method.FieldIndex = concat(index, method.FieldIndex) // make a copy of index
				// debugf("methodByName: %d-th explicit method of <%v> matches: %#v", i, t.rtype, method)
			}
			count++
		}
	}
	return
}

// return true if gmethod name matches given name
func matchMethodByName(qname QName, gmethod *types.Func) bool {
	// always check the methods's package, not the type's package
	return qname == QNameGo(gmethod)
}

// add method to type's methodcache. used by Type.MethodByName after a successful lookup
func cacheMethodByName(t *xtype, qname QName, method *Method, count int) {
	if t.methodcache == nil {
		t.methodcache = make(map[QName]Method)
	}
	if count > 1 {
		method.Index = -count // marker for ambiguous method names
	}
	t.methodcache[qname] = *method
	t.universe.methodcache = true
}

// visit type's direct and embedded fields in breadth-first order
func (v *Universe) VisitFields(t Type, visitor func(StructField)) {
	xt := unwrap(t)
	if xt == nil {
		return
	}
	var curr, tovisit []*xtype
	curr = []*xtype{xt}
	var seen typeutil.Map

	for len(curr) != 0 {
		for _, xt := range curr {
			// embedded fields can be named types or pointers to named types
			xt, _ = derefStruct(xt)
			if xt == nil || xt.kind != reflect.Struct || seen.At(xt.gtype) != nil {
				continue
			}
			seen.Set(xt.gtype, xt.gtype)

			for i, n := 0, xt.NumField(); i < n; i++ {
				field := xt.field(i)
				visitor(field)
				if field.Anonymous {
					tovisit = append(tovisit, unwrap(field.Type))
				}
			}
		}
		curr = tovisit
		tovisit = nil
	}
}

func invalidateCache(gtype types.Type, t interface{}) {
	if t, ok := t.(Type); ok {
		t := unwrap(t)
		t.fieldcache = nil
		t.methodcache = nil
	}
}

func invalidateMethodCache(gtype types.Type, t interface{}) {
	if t, ok := t.(Type); ok {
		t := unwrap(t)
		t.methodcache = nil
	}
}

// clears all xtype.fieldcache and xtype.methodcache.
// invoked by NamedOf() when a type is redefined.
func (v *Universe) InvalidateCache() {
	if v.fieldcache || v.methodcache {
		v.gmap.Iterate(invalidateCache)
		v.fieldcache = false
		v.methodcache = false
	}
}

// clears all xtype.methodcache.
// invoked by AddMethod() when a method is redefined.
func (v *Universe) InvalidateMethodCache() {
	if v.methodcache {
		v.gmap.Iterate(invalidateMethodCache)
		v.methodcache = false
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/negroni"
	"github.com/ello/ello-go/streams/api"
	"github.com/ello/ello-go/streams/service"
	"github.com/ello/ello-go/streams/util"
	"github.com/julienschmidt/httprouter"
	nlog "github.com/meatballhat/negroni-logrus"
	librato "github.com/mihasya/go-metrics-librato"
	"github.com/rcrowley/go-metrics"
)

var commit string
var startTime = time.Now()
var help bool
var helpMessage = `ELLO STREAM API
--------------------------
Set ENV Variables to configure:

ELLO_API_PORT for the port to run this service on.  Default is 8080
ELLO_ROSHI_HOST for the location of the roshi instance.  Default is http://localhost:6302
ELLO_AUTH_ENABLED any value will enable basic auth.  Default is disabled.
ELLO_AUTH_USERNAME for the auth username.  Default is 'ello'.
ELLO_AUTH_PASSWORD for the auth password.  Default is 'password'.
ELLO_LOG_LEVEL for the log level.  Valid levels are "debug", "info", "warn", "error"
ELLO_LIBRATO_EMAIL librato config
ELLO_LIBRATO_TOKEN librato config
ELLO_LIBRATO_HOSTNAME librato config
`

func main() {

	flag.BoolVar(&help, "h", false, "help?")
	flag.Parse()

	if help {
		fmt.Println(helpMessage)
		os.Exit(0)
	}

	var logLevel log.Level

	switch util.GetEnvWithDefault("ELLO_LOG_LEVEL", "warn") {
	case "debug":
		logLevel = log.DebugLevel
	case "info":
		logLevel = log.InfoLevel
	case "error":
		logLevel = log.ErrorLevel
	default:
		logLevel = log.WarnLevel
	}

	log.SetLevel(logLevel)
	fmt.Printf("Using log level [%v]\n", logLevel)

	roshi := util.GetEnvWithDefault("ELLO_ROSHI_HOST", "http://localhost:6302")
	streamsService, err := service.NewRoshiStreamService(roshi)
	if err != nil {
		log.Panic(err)
	}

	authConfig := api.AuthConfig{
		Username: []byte(util.GetEnvWithDefault("ELLO_AUTH_USERNAME", "ello")),
		Password: []byte(util.GetEnvWithDefault("ELLO_AUTH_PASSWORD", "password")),
		Enabled:  util.IsEnvPresent("ELLO_AUTH_ENABLED"),
	}
	log.Infof(authConfig.String())

	if util.IsEnvPresent("ELLO_LIBRATO_TOKEN") {
		go librato.Librato(metrics.DefaultRegistry,
			10e9, // interval
			// account owner email address
			util.GetEnvWithDefault("ELLO_LIBRATO_EMAIL", "***REMOVED***"), //TODO Change/remove before oss
			// Librato API token
			util.GetEnvWithDefault("ELLO_LIBRATO_TOKEN", "***REMOVED***"),
			util.GetEnvWithDefault("ELLO_LIBRATO_HOSTNAME", "ello"), // source
			[]float64{0.95},                                         // percentiles to send
			time.Millisecond,                                        // time unit
		)
	}

	router := httprouter.New()

	streamsController := api.NewStreamController(streamsService, authConfig)
	streamsController.Register(router)

	healthController := api.NewHealthController(startTime, commit, roshi)
	healthController.Register(router)

	n := negroni.New(
		negroni.NewRecovery(),
		nlog.NewCustomMiddleware(logLevel, &log.TextFormatter{}, "web"),
	)
	n.UseHandler(router)

	port := util.GetEnvWithDefault("ELLO_API_PORT", "8080")
	serverAt := ":" + port
	n.Run(serverAt)
}
<commit_msg>changed librato config<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/negroni"
	"github.com/ello/ello-go/streams/api"
	"github.com/ello/ello-go/streams/service"
	"github.com/ello/ello-go/streams/util"
	"github.com/julienschmidt/httprouter"
	nlog "github.com/meatballhat/negroni-logrus"
	librato "github.com/mihasya/go-metrics-librato"
	"github.com/rcrowley/go-metrics"
)

var commit string
var startTime = time.Now()
var help bool
var helpMessage = `ELLO STREAM API
--------------------------
Set ENV Variables to configure:

ELLO_API_PORT for the port to run this service on.  Default is 8080
ELLO_ROSHI_HOST for the location of the roshi instance.  Default is http://localhost:6302
ELLO_AUTH_ENABLED any value will enable basic auth.  Default is disabled.
ELLO_AUTH_USERNAME for the auth username.  Default is 'ello'.
ELLO_AUTH_PASSWORD for the auth password.  Default is 'password'.
ELLO_LOG_LEVEL for the log level.  Valid levels are "debug", "info", "warn", "error"
ELLO_LIBRATO_EMAIL librato config
ELLO_LIBRATO_TOKEN librato config
ELLO_LIBRATO_HOSTNAME librato config
`

func main() {

	flag.BoolVar(&help, "h", false, "help?")
	flag.Parse()

	if help {
		fmt.Println(helpMessage)
		os.Exit(0)
	}

	var logLevel log.Level

	switch util.GetEnvWithDefault("ELLO_LOG_LEVEL", "warn") {
	case "debug":
		logLevel = log.DebugLevel
	case "info":
		logLevel = log.InfoLevel
	case "error":
		logLevel = log.ErrorLevel
	default:
		logLevel = log.WarnLevel
	}

	log.SetLevel(logLevel)
	fmt.Printf("Using log level [%v]\n", logLevel)

	roshi := util.GetEnvWithDefault("ELLO_ROSHI_HOST", "http://localhost:6302")
	streamsService, err := service.NewRoshiStreamService(roshi)
	if err != nil {
		log.Panic(err)
	}

	authConfig := api.AuthConfig{
		Username: []byte(util.GetEnvWithDefault("ELLO_AUTH_USERNAME", "ello")),
		Password: []byte(util.GetEnvWithDefault("ELLO_AUTH_PASSWORD", "password")),
		Enabled:  util.IsEnvPresent("ELLO_AUTH_ENABLED"),
	}
	log.Infof(authConfig.String())

	if util.IsEnvPresent("ELLO_LIBRATO_TOKEN") {
		go librato.Librato(metrics.DefaultRegistry,
			10e9, // interval
			os.Getenv("ELLO_LIBRATO_EMAIL"),    // account owner email address
			os.Getenv("ELLO_LIBRATO_TOKEN"),    // Librato API token
			os.Getenv("ELLO_LIBRATO_HOSTNAME"), // source
			[]float64{0.95},                    // percentiles to send
			time.Millisecond,                   // time unit
		)
	}

	router := httprouter.New()

	streamsController := api.NewStreamController(streamsService, authConfig)
	streamsController.Register(router)

	healthController := api.NewHealthController(startTime, commit, roshi)
	healthController.Register(router)

	n := negroni.New(
		negroni.NewRecovery(),
		nlog.NewCustomMiddleware(logLevel, &log.TextFormatter{}, "web"),
	)
	n.UseHandler(router)

	port := util.GetEnvWithDefault("ELLO_API_PORT", "8080")
	serverAt := ":" + port
	n.Run(serverAt)
}
<|endoftext|>