<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"path/filepath"
	"time"

	twodee "../libs/twodee"
	"github.com/kurrik/tmxgo"
)

type Level struct {
	Height                      float32
	Grids                       []*twodee.Grid
	Items                       [][]*Item
	Geometry                    []*twodee.Batch
	GridRatios                  []float32
	Layers                      int32
	Player                      *Player
	Active                      int32
	Transitions                 []*LinearTween
	eventSystem                 *twodee.GameEventHandler
	onPlayerMoveEventId         int
	onPlayerPickedUpItemEventId int
	WaterAccumulation           time.Duration
}

func LoadLevel(path string, names []string, eventSystem *twodee.GameEventHandler) (l *Level, err error) {
	var player = NewPlayer(2, 2)
	l = &Level{
		Height:            0,
		Grids:             []*twodee.Grid{},
		Items:             [][]*Item{},
		Geometry:          []*twodee.Batch{},
		GridRatios:        []float32{},
		Layers:            0,
		Active:            0,
		Player:            player,
		eventSystem:       eventSystem,
		WaterAccumulation: 0,
	}
	l.onPlayerMoveEventId = eventSystem.AddObserver(PlayerMove, l.OnPlayerMoveEvent)
	l.onPlayerPickedUpItemEventId = eventSystem.AddObserver(PlayerPickedUpItem, l.OnPlayerPickedUpItemEvent)
	for _, name := range names {
		if err = l.loadLayer(path, name); err != nil {
			return
		}
	}
	return
}

const LevelWaterThreshold time.Duration = time.Duration(30) * time.Second

type LayerWaterStatus int

const (
	Dry LayerWaterStatus = iota
	Wet
	Flooded
)

const PxPerUnit float32 = 16.0

func (l *Level) loadLayer(path, name string) (err error) {
	var (
		tilemeta twodee.TileMetadata
		maptiles []*tmxgo.Tile
		textiles []twodee.TexturedTile
		maptile  *tmxgo.Tile
		m        *tmxgo.Map
		i        int
		data     []byte
		height   float32
		grid     *twodee.Grid
		items    []*Item
		batch    *twodee.Batch
		ratio    float32
	)
	path = filepath.Join(filepath.Dir(path), name)
	if data, err = ioutil.ReadFile(path); err != nil {
		return
	}
	if m, err = tmxgo.ParseMapString(string(data)); err != nil {
		return
	}
	if path, err = getTexturePath(m, path); err != nil {
		return
	}
	tilemeta = twodee.TileMetadata{
		Path:      path,
		PxPerUnit: int(PxPerUnit),
	}
	if maptiles, err = m.TilesFromLayerName("entities"); err != nil {
		return
	}
	for i, maptile = range maptiles {
		if maptile != nil {
			itemId := ItemId(maptile.Index)
			items = append(items, NewItem(
				itemId,
				ItemIdToType[itemId],
				"item",
				(maptile.TileBounds.X+maptile.TileBounds.W)/PxPerUnit,
				(maptile.TileBounds.Y+maptile.TileBounds.H)/PxPerUnit,
				maptile.TileBounds.W/PxPerUnit,
				maptile.TileBounds.H/PxPerUnit,
			))
		}
	}
	if maptiles, err = m.TilesFromLayerName("collision"); err != nil {
		return
	}
	grid = twodee.NewGrid(m.Width, m.Height)
	for i, maptile = range maptiles {
		if maptile != nil {
			grid.SetIndex(int32(i), true)
		}
	}
	if maptiles, err = m.TilesFromLayerName("tiles"); err != nil {
		return
	}
	textiles = make([]twodee.TexturedTile, len(maptiles))
	for i, maptile = range maptiles {
		if maptile != nil {
			textiles[i] = maptile
		}
	}
	if batch, err = twodee.LoadBatch(textiles, tilemeta); err != nil {
		return
	}
	//batch.SetTextureOffsetPx(0, 16)
	ratio = float32(grid.Width) * PxPerUnit / float32(m.TileWidth*m.Width)
	height = float32(grid.Height) / ratio
	if l.Height < height {
		l.Height = height
	}
	l.Grids = append(l.Grids, grid)
	l.Items = append(l.Items, items)
	l.Geometry = append(l.Geometry, batch)
	l.Layers += 1
	l.Transitions = append(l.Transitions, nil)
	l.GridRatios = append(l.GridRatios, ratio)
	return
}

func getTexturePath(m *tmxgo.Map, path string) (out string, err error) {
	var prefix = filepath.Dir(path)
	for i := 0; i < len(m.Tilesets); i++ {
		if m.Tilesets[i].Image == nil {
			continue
		}
		out = filepath.Join(prefix, m.Tilesets[i].Image.Source)
		return
	}
	err = fmt.Errorf("Could not find suitable tileset")
	return
}

func (l *Level) Delete() {
	var i int32
	for i = 0; i < l.Layers; i++ {
		l.Geometry[i].Delete()
	}
	l.eventSystem.RemoveObserver(PlayerMove, l.onPlayerMoveEventId)
	l.eventSystem.RemoveObserver(PlayerPickedUpItem, l.onPlayerPickedUpItemEventId)
}

func (l *Level) OnPlayerMoveEvent(e twodee.GETyper) {
	if move, ok := e.(*PlayerMoveEvent); ok {
		l.Player.UpdateDesiredMove(move.Dir, move.Inverse)
		//		l.Player.DesiredMove = move.Dir
	}
}

func (l *Level) OnPlayerPickedUpItemEvent(e twodee.GETyper) {
	if !l.Player.CanGetItem {
		return
	}
	if pickup, ok := e.(*PlayerPickedUpItemEvent); ok {
		l.Player.CanGetItem = false
		switch pickup.Item.Type {
		case LayerThresholdItem:
			l.Player.MoveTo(pickup.Item.Pos())
			l.Player.CanMove = false
			switch pickup.Item.Id {
			case ItemUp:
				l.LayerRewind()
			case ItemDown:
				l.LayerAdvance()
			}
		case InventoryItem:
			l.RemoveItem(pickup.Item)
			l.Player.AddToInventory(pickup.Item)
		}
	}
}

// Removes the item from the current layer's Items slice.
func (l *Level) RemoveItem(item *Item) {
	layerItems := l.Items[l.Active]
	index := -1
	for i, levelItem := range layerItems {
		if levelItem == item {
			index = i
			break
		}
	}
	if index != -1 {
		layerItems = append(layerItems[:index], layerItems[index+1:]...)
	}
}

func (l *Level) GridAlignedX(layer int32, p twodee.Point) twodee.Point {
	var (
		ratio = l.GridRatios[layer]
		x     = int32(p.X*ratio + 0.5)
	)
	return twodee.Pt(float32(x)/ratio, p.Y)
}

func (l *Level) GridAlignedY(layer int32, p twodee.Point) twodee.Point {
	var (
		ratio = l.GridRatios[layer]
		y     = int32(p.Y*ratio + 0.5)
	)
	return twodee.Pt(p.X, float32(y)/ratio)
}

// Given points a,b defining the leading edge of a moving entity; determine
// if there is a collision with something on the grid.
func (l *Level) FrontierCollides(layer int32, a, b twodee.Point) bool {
	var (
		ratio = l.GridRatios[layer]
		xmin  = int32(a.X * ratio)
		xmax  = int32(b.X * ratio)
		ymin  = int32(a.Y * ratio)
		ymax  = int32(b.Y * ratio)
	)
	// fmt.Printf("X %v-%v, Y %v-%v\n", xmin, xmax, ymin, ymax)
	for x := xmin; x <= xmax; x++ {
		for y := ymin; y <= ymax; y++ {
			// fmt.Printf("Checking X %v Y %v\n", x, y)
			if l.Grids[layer].Get(x, y) == true {
				return true
			}
		}
	}
	playerBounds := l.Player.Bounds()
	touchedItem := false
	for _, item := range l.Items[layer] {
		if playerBounds.Overlaps(item.Bounds()) {
			l.eventSystem.Enqueue(NewPlayerPickedUpItemEvent(item))
			touchedItem = true
			break
		}
	}
	// TODO(wes): Maybe remove this once items go away after pickup.
	if !touchedItem {
		// Prevent the player from triggering another item
		// pickup until they've moved off of all items
		l.Player.CanGetItem = true
	}
	return false
}

func (l *Level) GetLayerY(index int32) float32 {
	var tween = l.Transitions[index]
	if tween != nil {
		return tween.Current()
	}
	switch {
	case index > l.Active:
		return -1
	case index < l.Active:
		return l.Height
	case index == l.Active:
		return 0
	}
	return 0
}

const TopSlideSpeed = time.Duration(320) * time.Millisecond
const BotSlideSpeed = time.Duration(320) * time.Millisecond

func (l *Level) LayerAdvance() {
	if l.Active >= l.Layers-1 {
		return
	}
	l.Transitions[l.Active] = NewLinearTween(0, l.Height, TopSlideSpeed)
	l.Player.SetState(Standing | Down)
	l.Transitions[l.Active].SetCallback(func() {
		l.Player.CanMove = true
	})
	l.Active++
	l.Transitions[l.Active] = NewLinearTween(-1, 0, BotSlideSpeed)
}

func (l *Level) LayerRewind() {
	if l.Active <= 0 {
		return
	}
	l.Transitions[l.Active-1] = NewLinearTween(l.Height, 0, TopSlideSpeed)
	l.Transitions[l.Active-1].SetCallback(func() {
		l.Active--
		l.Player.SetState(ClimbUp | Down)
		l.Player.SetCallback(func() {
			l.Player.CanMove = true
			l.Player.SetState(Standing | Down)
		})
	})
	l.Transitions[l.Active] = NewLinearTween(0, -1, BotSlideSpeed)
}

func (l *Level) Update(elapsed time.Duration) {
	var i int32
	for i = 0; i < l.Layers; i++ {
		if l.Transitions[i] != nil {
			if l.Transitions[i].Done() {
				l.Transitions[i] = nil
			} else {
				l.Transitions[i].Update(elapsed)
			}
		}
	}
	l.Player.Update(elapsed)
	l.Player.AttemptMove(l)
	l.WaterAccumulation += elapsed
}

func (l *Level) GetLayerWaterStatus(layer int32) LayerWaterStatus {
	var percentFlooded = float32(l.WaterAccumulation) / float32(LevelWaterThreshold)
	if percentFlooded >= 1 {
		return Flooded
	}
	var layerLevelBottom = 1 - float32(layer)/float32(l.Layers)
	var layerLevelTop = layerLevelBottom + (1.00 / float32(l.Layers))
	if percentFlooded >= layerLevelTop {
		return Flooded
	} else if percentFlooded >= layerLevelBottom {
		return Wet
	}
	return Dry
}
<commit_msg>Make sure we don't leak underlying Items from the layer.<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"path/filepath"
	"time"

	twodee "../libs/twodee"
	"github.com/kurrik/tmxgo"
)

type Level struct {
	Height                      float32
	Grids                       []*twodee.Grid
	Items                       [][]*Item
	Geometry                    []*twodee.Batch
	GridRatios                  []float32
	Layers                      int32
	Player                      *Player
	Active                      int32
	Transitions                 []*LinearTween
	eventSystem                 *twodee.GameEventHandler
	onPlayerMoveEventId         int
	onPlayerPickedUpItemEventId int
	WaterAccumulation           time.Duration
}

func LoadLevel(path string, names []string, eventSystem *twodee.GameEventHandler) (l *Level, err error) {
	var player = NewPlayer(2, 2)
	l = &Level{
		Height:            0,
		Grids:             []*twodee.Grid{},
		Items:             [][]*Item{},
		Geometry:          []*twodee.Batch{},
		GridRatios:        []float32{},
		Layers:            0,
		Active:            0,
		Player:            player,
		eventSystem:       eventSystem,
		WaterAccumulation: 0,
	}
	l.onPlayerMoveEventId = eventSystem.AddObserver(PlayerMove, l.OnPlayerMoveEvent)
	l.onPlayerPickedUpItemEventId = eventSystem.AddObserver(PlayerPickedUpItem, l.OnPlayerPickedUpItemEvent)
	for _, name := range names {
		if err = l.loadLayer(path, name); err != nil {
			return
		}
	}
	return
}

const LevelWaterThreshold time.Duration = time.Duration(30) * time.Second

type LayerWaterStatus int

const (
	Dry LayerWaterStatus = iota
	Wet
	Flooded
)

const PxPerUnit float32 = 16.0

func (l *Level) loadLayer(path, name string) (err error) {
	var (
		tilemeta twodee.TileMetadata
		maptiles []*tmxgo.Tile
		textiles []twodee.TexturedTile
		maptile  *tmxgo.Tile
		m        *tmxgo.Map
		i        int
		data     []byte
		height   float32
		grid     *twodee.Grid
		items    []*Item
		batch    *twodee.Batch
		ratio    float32
	)
	path = filepath.Join(filepath.Dir(path), name)
	if data, err = ioutil.ReadFile(path); err != nil {
		return
	}
	if m, err = tmxgo.ParseMapString(string(data)); err != nil {
		return
	}
	if path, err = getTexturePath(m, path); err != nil {
		return
	}
	tilemeta = twodee.TileMetadata{
		Path:      path,
		PxPerUnit: int(PxPerUnit),
	}
	if maptiles, err = m.TilesFromLayerName("entities"); err != nil {
		return
	}
	for i, maptile = range maptiles {
		if maptile != nil {
			itemId := ItemId(maptile.Index)
			items = append(items, NewItem(
				itemId,
				ItemIdToType[itemId],
				"item",
				(maptile.TileBounds.X+maptile.TileBounds.W)/PxPerUnit,
				(maptile.TileBounds.Y+maptile.TileBounds.H)/PxPerUnit,
				maptile.TileBounds.W/PxPerUnit,
				maptile.TileBounds.H/PxPerUnit,
			))
		}
	}
	if maptiles, err = m.TilesFromLayerName("collision"); err != nil {
		return
	}
	grid = twodee.NewGrid(m.Width, m.Height)
	for i, maptile = range maptiles {
		if maptile != nil {
			grid.SetIndex(int32(i), true)
		}
	}
	if maptiles, err = m.TilesFromLayerName("tiles"); err != nil {
		return
	}
	textiles = make([]twodee.TexturedTile, len(maptiles))
	for i, maptile = range maptiles {
		if maptile != nil {
			textiles[i] = maptile
		}
	}
	if batch, err = twodee.LoadBatch(textiles, tilemeta); err != nil {
		return
	}
	//batch.SetTextureOffsetPx(0, 16)
	ratio = float32(grid.Width) * PxPerUnit / float32(m.TileWidth*m.Width)
	height = float32(grid.Height) / ratio
	if l.Height < height {
		l.Height = height
	}
	l.Grids = append(l.Grids, grid)
	l.Items = append(l.Items, items)
	l.Geometry = append(l.Geometry, batch)
	l.Layers += 1
	l.Transitions = append(l.Transitions, nil)
	l.GridRatios = append(l.GridRatios, ratio)
	return
}

func getTexturePath(m *tmxgo.Map, path string) (out string, err error) {
	var prefix = filepath.Dir(path)
	for i := 0; i < len(m.Tilesets); i++ {
		if m.Tilesets[i].Image == nil {
			continue
		}
		out = filepath.Join(prefix, m.Tilesets[i].Image.Source)
		return
	}
	err = fmt.Errorf("Could not find suitable tileset")
	return
}

func (l *Level) Delete() {
	var i int32
	for i = 0; i < l.Layers; i++ {
		l.Geometry[i].Delete()
	}
	l.eventSystem.RemoveObserver(PlayerMove, l.onPlayerMoveEventId)
	l.eventSystem.RemoveObserver(PlayerPickedUpItem, l.onPlayerPickedUpItemEventId)
}

func (l *Level) OnPlayerMoveEvent(e twodee.GETyper) {
	if move, ok := e.(*PlayerMoveEvent); ok {
		l.Player.UpdateDesiredMove(move.Dir, move.Inverse)
		//		l.Player.DesiredMove = move.Dir
	}
}

func (l *Level) OnPlayerPickedUpItemEvent(e twodee.GETyper) {
	if !l.Player.CanGetItem {
		return
	}
	if pickup, ok := e.(*PlayerPickedUpItemEvent); ok {
		l.Player.CanGetItem = false
		switch pickup.Item.Type {
		case LayerThresholdItem:
			l.Player.MoveTo(pickup.Item.Pos())
			l.Player.CanMove = false
			switch pickup.Item.Id {
			case ItemUp:
				l.LayerRewind()
			case ItemDown:
				l.LayerAdvance()
			}
		case InventoryItem:
			l.RemoveItem(pickup.Item)
			l.Player.AddToInventory(pickup.Item)
		}
	}
}

// Removes the item from the current layer's Items slice.
func (l *Level) RemoveItem(item *Item) {
	layerItems := l.Items[l.Active]
	index := -1
	for i, levelItem := range layerItems {
		if levelItem == item {
			index = i
			break
		}
	}
	if index != -1 {
		copy(layerItems[index:], layerItems[index+1:])
		layerItems[len(layerItems)-1] = nil
		layerItems = layerItems[:len(layerItems)-1]
		// Be sure to update the slice on the the level.
		l.Items[l.Active] = layerItems
	}
}

func (l *Level) GridAlignedX(layer int32, p twodee.Point) twodee.Point {
	var (
		ratio = l.GridRatios[layer]
		x     = int32(p.X*ratio + 0.5)
	)
	return twodee.Pt(float32(x)/ratio, p.Y)
}

func (l *Level) GridAlignedY(layer int32, p twodee.Point) twodee.Point {
	var (
		ratio = l.GridRatios[layer]
		y     = int32(p.Y*ratio + 0.5)
	)
	return twodee.Pt(p.X, float32(y)/ratio)
}

// Given points a,b defining the leading edge of a moving entity; determine
// if there is a collision with something on the grid.
func (l *Level) FrontierCollides(layer int32, a, b twodee.Point) bool {
	var (
		ratio = l.GridRatios[layer]
		xmin  = int32(a.X * ratio)
		xmax  = int32(b.X * ratio)
		ymin  = int32(a.Y * ratio)
		ymax  = int32(b.Y * ratio)
	)
	// fmt.Printf("X %v-%v, Y %v-%v\n", xmin, xmax, ymin, ymax)
	for x := xmin; x <= xmax; x++ {
		for y := ymin; y <= ymax; y++ {
			// fmt.Printf("Checking X %v Y %v\n", x, y)
			if l.Grids[layer].Get(x, y) == true {
				return true
			}
		}
	}
	playerBounds := l.Player.Bounds()
	touchedItem := false
	for _, item := range l.Items[layer] {
		if playerBounds.Overlaps(item.Bounds()) {
			l.eventSystem.Enqueue(NewPlayerPickedUpItemEvent(item))
			touchedItem = true
			break
		}
	}
	// TODO(wes): Maybe remove this once items go away after pickup.
	if !touchedItem {
		// Prevent the player from triggering another item
		// pickup until they've moved off of all items
		l.Player.CanGetItem = true
	}
	return false
}

func (l *Level) GetLayerY(index int32) float32 {
	var tween = l.Transitions[index]
	if tween != nil {
		return tween.Current()
	}
	switch {
	case index > l.Active:
		return -1
	case index < l.Active:
		return l.Height
	case index == l.Active:
		return 0
	}
	return 0
}

const TopSlideSpeed = time.Duration(320) * time.Millisecond
const BotSlideSpeed = time.Duration(320) * time.Millisecond

func (l *Level) LayerAdvance() {
	if l.Active >= l.Layers-1 {
		return
	}
	l.Transitions[l.Active] = NewLinearTween(0, l.Height, TopSlideSpeed)
	l.Player.SetState(Standing | Down)
	l.Transitions[l.Active].SetCallback(func() {
		l.Player.CanMove = true
	})
	l.Active++
	l.Transitions[l.Active] = NewLinearTween(-1, 0, BotSlideSpeed)
}

func (l *Level) LayerRewind() {
	if l.Active <= 0 {
		return
	}
	l.Transitions[l.Active-1] = NewLinearTween(l.Height, 0, TopSlideSpeed)
	l.Transitions[l.Active-1].SetCallback(func() {
		l.Active--
		l.Player.SetState(ClimbUp | Down)
		l.Player.SetCallback(func() {
			l.Player.CanMove = true
			l.Player.SetState(Standing | Down)
		})
	})
	l.Transitions[l.Active] = NewLinearTween(0, -1, BotSlideSpeed)
}

func (l *Level) Update(elapsed time.Duration) {
	var i int32
	for i = 0; i < l.Layers; i++ {
		if l.Transitions[i] != nil {
			if l.Transitions[i].Done() {
				l.Transitions[i] = nil
			} else {
				l.Transitions[i].Update(elapsed)
			}
		}
	}
	l.Player.Update(elapsed)
	l.Player.AttemptMove(l)
	l.WaterAccumulation += elapsed
}

func (l *Level) GetLayerWaterStatus(layer int32) LayerWaterStatus {
	var percentFlooded = float32(l.WaterAccumulation) / float32(LevelWaterThreshold)
	if percentFlooded >= 1 {
		return Flooded
	}
	var layerLevelBottom = 1 - float32(layer)/float32(l.Layers)
	var layerLevelTop = layerLevelBottom + (1.00 / float32(l.Layers))
	if percentFlooded >= layerLevelTop {
		return Flooded
	} else if percentFlooded >= layerLevelBottom {
		return Wet
	}
	return Dry
}
<|endoftext|>


<commit_before>package typescriptify

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"strings"
)

type TypeScriptify struct {
	Prefix         string
	Suffix         string
	Indent         string
	FromJSONMethod bool

	golangTypes []reflect.Type
	types       map[reflect.Kind]string

	// throwaway, used when converting
	alreadyConverted map[reflect.Type]bool
}

func New() *TypeScriptify {
	result := new(TypeScriptify)
	result.Indent = "\t"

	types := make(map[reflect.Kind]string)

	types[reflect.Bool] = "boolean"

	types[reflect.Int] = "number"
	types[reflect.Int8] = "number"
	types[reflect.Int16] = "number"
	types[reflect.Int32] = "number"
	types[reflect.Int64] = "number"
	types[reflect.Uint] = "number"
	types[reflect.Uint8] = "number"
	types[reflect.Uint16] = "number"
	types[reflect.Uint32] = "number"
	types[reflect.Uint64] = "number"
	types[reflect.Float32] = "number"
	types[reflect.Float64] = "number"

	types[reflect.String] = "string"

	result.types = types

	return result
}

func (this *TypeScriptify) Add(obj interface{}) {
	this.AddType(reflect.TypeOf(obj))
}

func (this *TypeScriptify) AddType(typeOf reflect.Type) {
	this.golangTypes = append(this.golangTypes, typeOf)
}

func (this *TypeScriptify) Convert(customCode map[string]string) (string, error) {
	this.alreadyConverted = make(map[reflect.Type]bool)

	result := ""
	for _, typeof := range this.golangTypes {
		typeScriptCode, err := this.convertType(typeof, customCode)
		if err != nil {
			return "", err
		}
		result += "\n" + strings.Trim(typeScriptCode, " "+this.Indent+"\r\n")
	}
	return result, nil
}

func loadCustomCode(fileName string) (map[string]string, error) {
	result := make(map[string]string)
	f, err := os.Open(fileName)
	if err != nil {
		if os.IsNotExist(err) {
			return result, nil
		}
		return result, err
	}
	defer f.Close()

	bytes, err := ioutil.ReadAll(f)
	if err != nil {
		return result, err
	}

	var currentName string
	var currentValue string
	lines := strings.Split(string(bytes), "\n")
	for _, line := range lines {
		trimmedLine := strings.TrimSpace(line)
		if strings.HasPrefix(trimmedLine, "//[") && strings.HasSuffix(trimmedLine, ":]") {
			currentName = strings.Replace(strings.Replace(trimmedLine, "//[", "", -1), ":]", "", -1)
			currentValue = ""
		} else if trimmedLine == "//[end]" {
			result[currentName] = strings.TrimRight(currentValue, " \t\r\n")
			currentName = ""
			currentValue = ""
		} else if len(currentName) > 0 {
			currentValue += line + "\n"
		}
	}

	return result, nil
}

func (this TypeScriptify) ConvertToFile(fileName string) error {
	customCode, err := loadCustomCode(fileName)
	if err != nil {
		return err
	}

	f, err := os.Create(fileName)
	if err != nil {
		return err
	}
	defer f.Close()

	converted, err := this.Convert(customCode)
	if err != nil {
		return err
	}

	f.WriteString("/* Do not change, this code is generated from Golang structs */\n\n")
	f.WriteString(converted)
	if err != nil {
		return err
	}

	return nil
}

func (this *TypeScriptify) convertType(typeOf reflect.Type, customCode map[string]string) (string, error) {
	if _, found := this.alreadyConverted[typeOf]; found { // Already converted
		return "", nil
	}

	entityName := fmt.Sprintf("%s%s%s", this.Prefix, this.Suffix, typeOf.Name())
	result := fmt.Sprintf("class %s {\n", entityName)
	builder := TypeScriptClassBuilder{
		types:  this.types,
		indent: this.Indent,
	}

	for i := 0; i < typeOf.NumField(); i++ {
		val := typeOf.Field(i)
		//fmt.Println("kind=", val.Type.Kind().String())
		jsonTag := val.Tag.Get("json")
		jsonFieldName := ""
		if len(jsonTag) > 0 {
			jsonTagParts := strings.Split(jsonTag, ",")
			if len(jsonTagParts) > 0 {
				jsonFieldName = strings.Trim(jsonTagParts[0], this.Indent)
			}
		}
		if len(jsonFieldName) > 0 && jsonFieldName != "-" {
			var err error
			if val.Type.Kind() == reflect.Struct { // Struct:
				typeScriptChunk, err := this.convertType(val.Type, customCode)
				if err != nil {
					return "", err
				}
				result = typeScriptChunk + "\n" + result
				builder.AddStructField(jsonFieldName, val.Type.Name())
			} else if val.Type.Kind() == reflect.Slice { // Slice:
				if val.Type.Elem().Kind() == reflect.Struct { // Slice of structs:
					typeScriptChunk, err := this.convertType(val.Type.Elem(), customCode)
					if err != nil {
						return "", err
					}
					result = typeScriptChunk + "\n" + result
					builder.AddArrayOfStructsField(jsonFieldName, val.Type.Elem().Name())
				} else { // Slice of simple fields:
					err = builder.AddSimpleArrayField(jsonFieldName, val.Type.Elem().Name(), val.Type.Elem().Kind())
				}
			} else { // Simple field:
				err = builder.AddSimpleField(jsonFieldName, val.Type.Name(), val.Type.Kind())
			}
			if err != nil {
				return "", err
			}
		}
	}

	result += builder.fields
	if this.FromJSONMethod {
		result += fmt.Sprintf("%sstatic fromJSON(json: any) {\n", this.Indent)
		result += fmt.Sprintf("%s%svar result = new %s();\n", this.Indent, this.Indent, entityName)
		result += builder.fromJSONMethodBody
		result += fmt.Sprintf("%s%sreturn result;\n", this.Indent, this.Indent)
		result += fmt.Sprintf("%s}\n", this.Indent)
	}

	if customCode != nil {
		code := customCode[entityName]
		result += this.Indent + "//[" + entityName + ":]\n" + code + "\n\n" + this.Indent + "//[end]\n"
	}

	result += "}"

	this.alreadyConverted[typeOf] = true

	return result, nil
}

type TypeScriptClassBuilder struct {
	types              map[reflect.Kind]string
	indent             string
	fields             string
	fromJSONMethodBody string
}

func (this *TypeScriptClassBuilder) AddSimpleArrayField(fieldName, fieldType string, kind reflect.Kind) error {
	if typeScriptType, ok := this.types[kind]; ok {
		if len(fieldName) > 0 {
			this.fields += fmt.Sprintf("%s%s: %s[];\n", this.indent, fieldName, typeScriptType)
			this.fromJSONMethodBody += fmt.Sprintf("%s%sresult.%s = json[\"%s\"];\n", this.indent, this.indent, fieldName, fieldName)
			return nil
		}
	}
	return errors.New(fmt.Sprintf("Cannot find type for %s (%s/%s)", kind.String(), fieldName, fieldType))
}

func (this *TypeScriptClassBuilder) AddSimpleField(fieldName, fieldType string, kind reflect.Kind) error {
	if typeScriptType, ok := this.types[kind]; ok {
		if len(fieldName) > 0 {
			this.fields += fmt.Sprintf("%s%s: %s;\n", this.indent, fieldName, typeScriptType)
			this.fromJSONMethodBody += fmt.Sprintf("%s%sresult.%s = json[\"%s\"];\n", this.indent, this.indent, fieldName, fieldName)
			return nil
		}
	}
	return errors.New("Cannot find type for " + fieldType)
}

func (this *TypeScriptClassBuilder) AddStructField(fieldName, fieldType string) {
	this.fields += fmt.Sprintf("%s%s: %s;\n", this.indent, fieldName, fieldType)
	this.fromJSONMethodBody += fmt.Sprintf("%s%sresult.%s = %s.fromJSON(json[\"%s\"]);\n", this.indent, this.indent, fieldName, fieldType, fieldName)
}

func (this *TypeScriptClassBuilder) AddArrayOfStructsField(fieldName, fieldType string) {
	this.fields += fmt.Sprintf("%s%s: %s[];\n", this.indent, fieldName, fieldType)
	this.fromJSONMethodBody += fmt.Sprintf("%s%sif (json[\"%s\"]) {\n", this.indent, this.indent, fieldName)
	this.fromJSONMethodBody += fmt.Sprintf("%s%s%sresult.%s = json[\"%s\"].map(function(element) { return %s.fromJSON(element); });\n", this.indent, this.indent, this.indent, fieldName, fieldName, fieldType)
	this.fromJSONMethodBody += fmt.Sprintf("%s%s}\n", this.indent, this.indent)
}
<commit_msg>Bettern name<commit_after>package typescriptify

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"strings"
)

type TypeScriptify struct {
	Prefix         string
	Suffix         string
	Indent         string
	FromJSONMethod bool

	golangTypes []reflect.Type
	types       map[reflect.Kind]string

	// throwaway, used when converting
	alreadyConverted map[reflect.Type]bool
}

func New() *TypeScriptify {
	result := new(TypeScriptify)
	result.Indent = "\t"

	types := make(map[reflect.Kind]string)

	types[reflect.Bool] = "boolean"

	types[reflect.Int] = "number"
	types[reflect.Int8] = "number"
	types[reflect.Int16] = "number"
	types[reflect.Int32] = "number"
	types[reflect.Int64] = "number"
	types[reflect.Uint] = "number"
	types[reflect.Uint8] = "number"
	types[reflect.Uint16] = "number"
	types[reflect.Uint32] = "number"
	types[reflect.Uint64] = "number"
	types[reflect.Float32] = "number"
	types[reflect.Float64] = "number"

	types[reflect.String] = "string"

	result.types = types

	return result
}

func (this *TypeScriptify) Add(obj interface{}) {
	this.AddType(reflect.TypeOf(obj))
}

func (this *TypeScriptify) AddType(typeOf reflect.Type) {
	this.golangTypes = append(this.golangTypes, typeOf)
}

func (this *TypeScriptify) Convert(customCode map[string]string) (string, error) {
	this.alreadyConverted = make(map[reflect.Type]bool)

	result := ""
	for _, typeof := range this.golangTypes {
		typeScriptCode, err := this.convertType(typeof, customCode)
		if err != nil {
			return "", err
		}
		result += "\n" + strings.Trim(typeScriptCode, " "+this.Indent+"\r\n")
	}
	return result, nil
}

func loadCustomCode(fileName string) (map[string]string, error) {
	result := make(map[string]string)
	f, err := os.Open(fileName)
	if err != nil {
		if os.IsNotExist(err) {
			return result, nil
		}
		return result, err
	}
	defer f.Close()

	bytes, err := ioutil.ReadAll(f)
	if err != nil {
		return result, err
	}

	var currentName string
	var currentValue string
	lines := strings.Split(string(bytes), "\n")
	for _, line := range lines {
		trimmedLine := strings.TrimSpace(line)
		if strings.HasPrefix(trimmedLine, "//[") && strings.HasSuffix(trimmedLine, ":]") {
			currentName = strings.Replace(strings.Replace(trimmedLine, "//[", "", -1), ":]", "", -1)
			currentValue = ""
		} else if trimmedLine == "//[end]" {
			result[currentName] = strings.TrimRight(currentValue, " \t\r\n")
			currentName = ""
			currentValue = ""
		} else if len(currentName) > 0 {
			currentValue += line + "\n"
		}
	}

	return result, nil
}

func (this TypeScriptify) ConvertToFile(fileName string) error {
	customCode, err := loadCustomCode(fileName)
	if err != nil {
		return err
	}

	f, err := os.Create(fileName)
	if err != nil {
		return err
	}
	defer f.Close()

	converted, err := this.Convert(customCode)
	if err != nil {
		return err
	}

	f.WriteString("/* Do not change, this code is generated from Golang structs */\n\n")
	f.WriteString(converted)
	if err != nil {
		return err
	}

	return nil
}

func (this *TypeScriptify) convertType(typeOf reflect.Type, customCode map[string]string) (string, error) {
	if _, found := this.alreadyConverted[typeOf]; found { // Already converted
		return "", nil
	}

	entityName := fmt.Sprintf("%s%s%s", this.Prefix, this.Suffix, typeOf.Name())
	result := fmt.Sprintf("class %s {\n", entityName)
	builder := TypeScriptClassBuilder{
		types:  this.types,
		indent: this.Indent,
	}

	for i := 0; i < typeOf.NumField(); i++ {
		val := typeOf.Field(i)
		//fmt.Println("kind=", val.Type.Kind().String())
		jsonTag := val.Tag.Get("json")
		jsonFieldName := ""
		if len(jsonTag) > 0 {
			jsonTagParts := strings.Split(jsonTag, ",")
			if len(jsonTagParts) > 0 {
				jsonFieldName = strings.Trim(jsonTagParts[0], this.Indent)
			}
		}
		if len(jsonFieldName) > 0 && jsonFieldName != "-" {
			var err error
			if val.Type.Kind() == reflect.Struct { // Struct:
				typeScriptChunk, err := this.convertType(val.Type, customCode)
				if err != nil {
					return "", err
				}
				result = typeScriptChunk + "\n" + result
				builder.AddStructField(jsonFieldName, val.Type.Name())
			} else if val.Type.Kind() == reflect.Slice { // Slice:
				if val.Type.Elem().Kind() == reflect.Struct { // Slice of structs:
					typeScriptChunk, err := this.convertType(val.Type.Elem(), customCode)
					if err != nil {
						return "", err
					}
					result = typeScriptChunk + "\n" + result
					builder.AddArrayOfStructsField(jsonFieldName, val.Type.Elem().Name())
				} else { // Slice of simple fields:
					err = builder.AddSimpleArrayField(jsonFieldName, val.Type.Elem().Name(), val.Type.Elem().Kind())
				}
			} else { // Simple field:
				err = builder.AddSimpleField(jsonFieldName, val.Type.Name(), val.Type.Kind())
			}
			if err != nil {
				return "", err
			}
		}
	}

	result += builder.fields
	if this.FromJSONMethod {
		result += fmt.Sprintf("%sstatic createFrom(source: any) {\n", this.Indent)
		result += fmt.Sprintf("%s%svar result = new %s();\n", this.Indent, this.Indent, entityName)
		result += builder.createFromMethodBody
		result += fmt.Sprintf("%s%sreturn result;\n", this.Indent, this.Indent)
		result += fmt.Sprintf("%s}\n", this.Indent)
	}

	if customCode != nil {
		code := customCode[entityName]
		result += this.Indent + "//[" + entityName + ":]\n" + code + "\n\n" + this.Indent + "//[end]\n"
	}

	result += "}"

	this.alreadyConverted[typeOf] = true

	return result, nil
}

type TypeScriptClassBuilder struct {
	types                map[reflect.Kind]string
	indent               string
	fields               string
	createFromMethodBody string
}

func (this *TypeScriptClassBuilder) AddSimpleArrayField(fieldName, fieldType string, kind reflect.Kind) error {
	if typeScriptType, ok := this.types[kind]; ok {
		if len(fieldName) > 0 {
			this.fields += fmt.Sprintf("%s%s: %s[];\n", this.indent, fieldName, typeScriptType)
			this.createFromMethodBody += fmt.Sprintf("%s%sresult.%s = source[\"%s\"];\n", this.indent, this.indent, fieldName, fieldName)
			return nil
		}
	}
	return errors.New(fmt.Sprintf("Cannot find type for %s (%s/%s)", kind.String(), fieldName, fieldType))
}

func (this *TypeScriptClassBuilder) AddSimpleField(fieldName, fieldType string, kind reflect.Kind) error {
	if typeScriptType, ok := this.types[kind]; ok {
		if len(fieldName) > 0 {
			this.fields += fmt.Sprintf("%s%s: %s;\n", this.indent, fieldName, typeScriptType)
			this.createFromMethodBody += fmt.Sprintf("%s%sresult.%s = source[\"%s\"];\n", this.indent, this.indent, fieldName, fieldName)
			return nil
		}
	}
	return errors.New("Cannot find type for " + fieldType)
}

func (this *TypeScriptClassBuilder) AddStructField(fieldName, fieldType string) {
	this.fields += fmt.Sprintf("%s%s: %s;\n", this.indent, fieldName, fieldType)
	this.createFromMethodBody += fmt.Sprintf("%s%sresult.%s = %s.source(json[\"%s\"]);\n", this.indent, this.indent, fieldName, fieldType, fieldName)
}

func (this *TypeScriptClassBuilder) AddArrayOfStructsField(fieldName, fieldType string) {
	this.fields += fmt.Sprintf("%s%s: %s[];\n", this.indent, fieldName, fieldType)
	this.createFromMethodBody += fmt.Sprintf("%s%sif (source[\"%s\"]) {\n", this.indent, this.indent, fieldName)
	this.createFromMethodBody += fmt.Sprintf("%s%s%sresult.%s = source[\"%s\"].map(function(element) { return %s.fromJSON(element); });\n", this.indent, this.indent, this.indent, fieldName, fieldName, fieldType)
	this.createFromMethodBody += fmt.Sprintf("%s%s}\n", this.indent, this.indent)
}
<|endoftext|>


<commit_before>package eventlog

import "testing"

func TestOverwrite(t *testing.T) {
	t.Parallel()

	under := Metadata{
		"a": Metadata{
			"b": Metadata{
				"c": Metadata{
					"d":     "the original value",
					"other": "SURVIVE",
				},
			},
		},
	}
	over := Metadata{
		"a": Metadata{
			"b": Metadata{
				"c": Metadata{
					"d": "a new value",
				},
			},
		},
	}

	out := DeepMerge(under, over)

	dval := out["a"].(Metadata)["b"].(Metadata)["c"].(Metadata)["d"].(string)
	if dval != "a new value" {
		t.Fatal(dval)
	}
	surv := out["a"].(Metadata)["b"].(Metadata)["c"].(Metadata)["other"].(string)
	if surv != "SURVIVE" {
		t.Fatal(surv)
	}
}

func TestMarshalJSON(t *testing.T) {
	bs, _ := Metadata{"a": "b"}.JsonString()
	t.Log(bs)
}

func TestMetadataIsLoggable(t *testing.T) {
	func(l Loggable) {
	}(Metadata{})
}
<commit_msg>misc(eventlog) run tests in parallel<commit_after>package eventlog

import "testing"

func TestOverwrite(t *testing.T) {
	t.Parallel()

	under := Metadata{
		"a": Metadata{
			"b": Metadata{
				"c": Metadata{
					"d":     "the original value",
					"other": "SURVIVE",
				},
			},
		},
	}
	over := Metadata{
		"a": Metadata{
			"b": Metadata{
				"c": Metadata{
					"d": "a new value",
				},
			},
		},
	}

	out := DeepMerge(under, over)

	dval := out["a"].(Metadata)["b"].(Metadata)["c"].(Metadata)["d"].(string)
	if dval != "a new value" {
		t.Fatal(dval)
	}
	surv := out["a"].(Metadata)["b"].(Metadata)["c"].(Metadata)["other"].(string)
	if surv != "SURVIVE" {
		t.Fatal(surv)
	}
}

func TestMarshalJSON(t *testing.T) {
	t.Parallel()
	bs, _ := Metadata{"a": "b"}.JsonString()
	t.Log(bs)
}

func TestMetadataIsLoggable(t *testing.T) {
	t.Parallel()
	func(l Loggable) {
	}(Metadata{})
}
<|endoftext|>


<commit_before>package packer

import (
	"fmt"
	"github.com/mitchellh/mapstructure"
	jsonutil "github.com/mitchellh/packer/common/json"
	"io/ioutil"
	"sort"
)

// The rawTemplate struct represents the structure of a template read
// directly from a file. The builders and other components map just to
// "interface{}" pointers since we actually don't know what their contents
// are until we read the "type" field.
type rawTemplate struct {
	Variables      map[string]string
	Builders       []map[string]interface{}
	Hooks          map[string][]string
	Provisioners   []map[string]interface{}
	PostProcessors []interface{} `mapstructure:"post-processors"`
}

// The Template struct represents a parsed template, parsed into the most
// completed form it can be without additional processing by the caller.
type Template struct {
	Variables      map[string]string
	Builders       map[string]rawBuilderConfig
	Hooks          map[string][]string
	PostProcessors [][]rawPostProcessorConfig
	Provisioners   []rawProvisionerConfig
}

// The rawBuilderConfig struct represents a raw, unprocessed builder
// configuration. It contains the name of the builder as well as the
// raw configuration. If requested, this is used to compile into a full
// builder configuration at some point.
type rawBuilderConfig struct {
	Name string
	Type string

	rawConfig interface{}
}

// rawPostProcessorConfig represents a raw, unprocessed post-processor
// configuration. It contains the type of the post processor as well as the
// raw configuration that is handed to the post-processor for it to process.
type rawPostProcessorConfig struct {
	Type              string
	KeepInputArtifact bool `mapstructure:"keep_input_artifact"`
	rawConfig         interface{}
}

// rawProvisionerConfig represents a raw, unprocessed provisioner configuration.
// It contains the type of the provisioner as well as the raw configuration
// that is handed to the provisioner for it to process.
type rawProvisionerConfig struct {
	Type     string
	Override map[string]interface{}

	rawConfig interface{}
}

// ParseTemplate takes a byte slice and parses a Template from it, returning
// the template and possibly errors while loading the template. The error
// could potentially be a MultiError, representing multiple errors. Knowing
// and checking for this can be useful, if you wish to format it in a certain
// way.
func ParseTemplate(data []byte) (t *Template, err error) {
	var rawTplInterface interface{}
	err = jsonutil.Unmarshal(data, &rawTplInterface)
	if err != nil {
		return
	}

	// Decode the raw template interface into the actual rawTemplate
	// structure, checking for any extranneous keys along the way.
	var md mapstructure.Metadata
	var rawTpl rawTemplate
	decoderConfig := &mapstructure.DecoderConfig{
		Metadata: &md,
		Result:   &rawTpl,
	}

	decoder, err := mapstructure.NewDecoder(decoderConfig)
	if err != nil {
		return
	}

	err = decoder.Decode(rawTplInterface)
	if err != nil {
		return
	}

	errors := make([]error, 0)

	if len(md.Unused) > 0 {
		sort.Strings(md.Unused)
		for _, unused := range md.Unused {
			errors = append(
				errors, fmt.Errorf("Unknown root level key in template: '%s'", unused))
		}
	}

	t = &Template{}
	t.Variables = make(map[string]string)
	t.Builders = make(map[string]rawBuilderConfig)
	t.Hooks = rawTpl.Hooks
	t.PostProcessors = make([][]rawPostProcessorConfig, len(rawTpl.PostProcessors))
	t.Provisioners = make([]rawProvisionerConfig, len(rawTpl.Provisioners))

	// Gather all the variables
	for k, v := range rawTpl.Variables {
		t.Variables[k] = v
	}

	// Gather all the builders
	for i, v := range rawTpl.Builders {
		var raw rawBuilderConfig
		if err := mapstructure.Decode(v, &raw); err != nil {
			if merr, ok := err.(*mapstructure.Error); ok {
				for _, err := range merr.Errors {
					errors = append(errors, fmt.Errorf("builder %d: %s", i+1, err))
				}
			} else {
				errors = append(errors, fmt.Errorf("builder %d: %s", i+1, err))
			}

			continue
		}

		if raw.Type == "" {
			errors = append(errors, fmt.Errorf("builder %d: missing 'type'", i+1))
			continue
		}

		// Attempt to get the name of the builder. If the "name" key
		// missing, use the "type" field, which is guaranteed to exist
		// at this point.
		if raw.Name == "" {
			raw.Name = raw.Type
		}

		// Check if we already have a builder with this name and error if so
		if _, ok := t.Builders[raw.Name]; ok {
			errors = append(errors, fmt.Errorf("builder with name '%s' already exists", raw.Name))
			continue
		}

		// Now that we have the name, remove it from the config - as the builder
		// itself doesn't know about, and it will cause a validation error.
		delete(v, "name")

		raw.rawConfig = v

		t.Builders[raw.Name] = raw
	}

	// Gather all the post-processors. This is a complicated process since there
	// are actually three different formats that the user can use to define
	// a post-processor.
	for i, rawV := range rawTpl.PostProcessors {
		rawPP, err := parsePostProvisioner(i, rawV)
		if err != nil {
			errors = append(errors, err...)
			continue
		}

		t.PostProcessors[i] = make([]rawPostProcessorConfig, len(rawPP))
		configs := t.PostProcessors[i]
		for j, pp := range rawPP {
			config := &configs[j]
			if err := mapstructure.Decode(pp, config); err != nil {
				if merr, ok := err.(*mapstructure.Error); ok {
					for _, err := range merr.Errors {
						errors = append(errors, fmt.Errorf("Post-processor #%d.%d: %s", i+1, j+1, err))
					}
				} else {
					errors = append(errors, fmt.Errorf("Post-processor %d.%d: %s", i+1, j+1, err))
				}

				continue
			}

			if config.Type == "" {
				errors = append(errors, fmt.Errorf("Post-processor %d.%d: missing 'type'", i+1, j+1))
				continue
			}

			config.rawConfig = pp
		}
	}

	// Gather all the provisioners
	for i, v := range rawTpl.Provisioners {
		raw := &t.Provisioners[i]
		if err := mapstructure.Decode(v, raw); err != nil {
			if merr, ok := err.(*mapstructure.Error); ok {
				for _, err := range merr.Errors {
					errors = append(errors, fmt.Errorf("provisioner %d: %s", i+1, err))
				}
			} else {
				errors = append(errors, fmt.Errorf("provisioner %d: %s", i+1, err))
			}

			continue
		}

		if raw.Type == "" {
			errors = append(errors, fmt.Errorf("provisioner %d: missing 'type'", i+1))
			continue
		}

		// The provisioners not only don't need or want the override settings
		// (as they are processed as part of the preparation below), but will
		// actively reject them as invalid configuration.
		delete(v, "override")

		raw.rawConfig = v
	}

	if len(t.Builders) == 0 {
		errors = append(errors, fmt.Errorf("No builders are defined in the template."))
	}

	// If there were errors, we put it into a MultiError and return
	if len(errors) > 0 {
		err = &MultiError{errors}
		t = nil
		return
	}

	return
}

// ParseTemplateFile takes the given template file and parses it into
// a single template.
func ParseTemplateFile(path string) (*Template, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	return ParseTemplate(data)
}

func parsePostProvisioner(i int, rawV interface{}) (result []map[string]interface{}, errors []error) {
	switch v := rawV.(type) {
	case string:
		result = []map[string]interface{}{
			{"type": v},
		}
	case map[string]interface{}:
		result = []map[string]interface{}{v}
	case []interface{}:
		result = make([]map[string]interface{}, len(v))
		errors = make([]error, 0)
		for j, innerRawV := range v {
			switch innerV := innerRawV.(type) {
			case string:
				result[j] = map[string]interface{}{"type": innerV}
			case map[string]interface{}:
				result[j] = innerV
			case []interface{}:
				errors = append(
					errors,
					fmt.Errorf("Post-processor %d.%d: sequences not allowed to be nested in sequences", i+1, j+1))
			default:
				errors = append(errors, fmt.Errorf("Post-processor %d.%d is in a bad format.", i+1, j+1))
			}
		}

		if len(errors) == 0 {
			errors = nil
		}
	default:
		result = nil
		errors = []error{fmt.Errorf("Post-processor %d is in a bad format.", i+1)}
	}

	return
}

// BuildNames returns a slice of the available names of builds that
// this template represents.
func (t *Template) BuildNames() []string {
	names := make([]string, 0, len(t.Builders))
	for name, _ := range t.Builders {
		names = append(names, name)
	}

	return names
}

// Build returns a Build for the given name.
//
// If the build does not exist as part of this template, an error is
// returned.
func (t *Template) Build(name string, components *ComponentFinder) (b Build, err error) {
	// Setup the Builder
	builderConfig, ok := t.Builders[name]
	if !ok {
		err = fmt.Errorf("No such build found in template: %s", name)
		return
	}

	// We panic if there is no builder function because this is really
	// an internal bug that always needs to be fixed, not an error.
	if components.Builder == nil {
		panic("no builder function")
	}

	// Panic if there are provisioners on the template but no provisioner
	// component finder. This is always an internal error, so we panic.
	if len(t.Provisioners) > 0 && components.Provisioner == nil {
		panic("no provisioner function")
	}

	builder, err := components.Builder(builderConfig.Type)
	if err != nil {
		return
	}

	if builder == nil {
		err = fmt.Errorf("Builder type not found: %s", builderConfig.Type)
		return
	}

	// Gather the Hooks
	hooks := make(map[string][]Hook)
	for tplEvent, tplHooks := range t.Hooks {
		curHooks := make([]Hook, 0, len(tplHooks))

		for _, hookName := range tplHooks {
			var hook Hook
			hook, err = components.Hook(hookName)
			if err != nil {
				return
			}

			if hook == nil {
				err = fmt.Errorf("Hook not found: %s", hookName)
				return
			}

			curHooks = append(curHooks, hook)
		}

		hooks[tplEvent] = curHooks
	}

	// Prepare the post-processors
	postProcessors := make([][]coreBuildPostProcessor, 0, len(t.PostProcessors))
	for _, rawPPs := range t.PostProcessors {
		current := make([]coreBuildPostProcessor, len(rawPPs))
		for i, rawPP := range rawPPs {
			pp, err := components.PostProcessor(rawPP.Type)
			if err != nil {
				return nil, err
			}

			if pp == nil {
				return nil, fmt.Errorf("PostProcessor type not found: %s", rawPP.Type)
			}

			current[i] = coreBuildPostProcessor{
				processor:         pp,
				processorType:     rawPP.Type,
				config:            rawPP.rawConfig,
				keepInputArtifact: rawPP.KeepInputArtifact,
			}
		}

		postProcessors = append(postProcessors, current)
	}

	// Prepare the provisioners
	provisioners := make([]coreBuildProvisioner, 0, len(t.Provisioners))
	for _, rawProvisioner := range t.Provisioners {
		var provisioner Provisioner
		provisioner, err = components.Provisioner(rawProvisioner.Type)
		if err != nil {
			return
		}

		if provisioner == nil {
			err = fmt.Errorf("Provisioner type not found: %s", rawProvisioner.Type)
			return
		}

		configs := make([]interface{}, 1, 2)
		configs[0] = rawProvisioner.rawConfig

		if rawProvisioner.Override != nil {
			if override, ok := rawProvisioner.Override[name]; ok {
				configs = append(configs, override)
			}
		}

		coreProv := coreBuildProvisioner{provisioner, configs}
		provisioners = append(provisioners, coreProv)
	}

	b = &coreBuild{
		name:           name,
		builder:        builder,
		builderConfig:  builderConfig.rawConfig,
		builderType:    builderConfig.Type,
		hooks:          hooks,
		postProcessors: postProcessors,
		provisioners:   provisioners,
		variables:      t.Variables,
	}

	return
}
<commit_msg>packer: Export the raw template config structs<commit_after>package packer

import (
	"fmt"
	"github.com/mitchellh/mapstructure"
	jsonutil "github.com/mitchellh/packer/common/json"
	"io/ioutil"
	"sort"
)

// The rawTemplate struct represents the structure of a template read
// directly from a file. The builders and other components map just to
// "interface{}" pointers since we actually don't know what their contents
// are until we read the "type" field.
type rawTemplate struct {
	Variables      map[string]string
	Builders       []map[string]interface{}
	Hooks          map[string][]string
	Provisioners   []map[string]interface{}
	PostProcessors []interface{} `mapstructure:"post-processors"`
}

// The Template struct represents a parsed template, parsed into the most
// completed form it can be without additional processing by the caller.
type Template struct {
	Variables      map[string]string
	Builders       map[string]RawBuilderConfig
	Hooks          map[string][]string
	PostProcessors [][]RawPostProcessorConfig
	Provisioners   []RawProvisionerConfig
}

// The RawBuilderConfig struct represents a raw, unprocessed builder
// configuration. It contains the name of the builder as well as the
// raw configuration. If requested, this is used to compile into a full
// builder configuration at some point.
type RawBuilderConfig struct {
	Name string
	Type string

	rawConfig interface{}
}

// RawPostProcessorConfig represents a raw, unprocessed post-processor
// configuration. It contains the type of the post processor as well as the
// raw configuration that is handed to the post-processor for it to process.
type RawPostProcessorConfig struct {
	Type              string
	KeepInputArtifact bool `mapstructure:"keep_input_artifact"`
	rawConfig         interface{}
}

// RawProvisionerConfig represents a raw, unprocessed provisioner configuration.
// It contains the type of the provisioner as well as the raw configuration
// that is handed to the provisioner for it to process.
type RawProvisionerConfig struct {
	Type     string
	Override map[string]interface{}

	rawConfig interface{}
}

// ParseTemplate takes a byte slice and parses a Template from it, returning
// the template and possibly errors while loading the template. The error
// could potentially be a MultiError, representing multiple errors. Knowing
// and checking for this can be useful, if you wish to format it in a certain
// way.
func ParseTemplate(data []byte) (t *Template, err error) {
	var rawTplInterface interface{}
	err = jsonutil.Unmarshal(data, &rawTplInterface)
	if err != nil {
		return
	}

	// Decode the raw template interface into the actual rawTemplate
	// structure, checking for any extranneous keys along the way.
	var md mapstructure.Metadata
	var rawTpl rawTemplate
	decoderConfig := &mapstructure.DecoderConfig{
		Metadata: &md,
		Result:   &rawTpl,
	}

	decoder, err := mapstructure.NewDecoder(decoderConfig)
	if err != nil {
		return
	}

	err = decoder.Decode(rawTplInterface)
	if err != nil {
		return
	}

	errors := make([]error, 0)

	if len(md.Unused) > 0 {
		sort.Strings(md.Unused)
		for _, unused := range md.Unused {
			errors = append(
				errors, fmt.Errorf("Unknown root level key in template: '%s'", unused))
		}
	}

	t = &Template{}
	t.Variables = make(map[string]string)
	t.Builders = make(map[string]RawBuilderConfig)
	t.Hooks = rawTpl.Hooks
	t.PostProcessors = make([][]RawPostProcessorConfig, len(rawTpl.PostProcessors))
	t.Provisioners = make([]RawProvisionerConfig, len(rawTpl.Provisioners))

	// Gather all the variables
	for k, v := range rawTpl.Variables {
		t.Variables[k] = v
	}

	// Gather all the builders
	for i, v := range rawTpl.Builders {
		var raw RawBuilderConfig
		if err := mapstructure.Decode(v, &raw); err != nil {
			if merr, ok := err.(*mapstructure.Error); ok {
				for _, err := range merr.Errors {
					errors = append(errors, fmt.Errorf("builder %d: %s", i+1, err))
				}
			} else {
				errors = append(errors, fmt.Errorf("builder %d: %s", i+1, err))
			}

			continue
		}

		if raw.Type == "" {
			errors = append(errors, fmt.Errorf("builder %d: missing 'type'", i+1))
			continue
		}

		// Attempt to get the name of the builder. If the "name" key
		// missing, use the "type" field, which is guaranteed to exist
		// at this point.
		if raw.Name == "" {
			raw.Name = raw.Type
		}

		// Check if we already have a builder with this name and error if so
		if _, ok := t.Builders[raw.Name]; ok {
			errors = append(errors, fmt.Errorf("builder with name '%s' already exists", raw.Name))
			continue
		}

		// Now that we have the name, remove it from the config - as the builder
		// itself doesn't know about, and it will cause a validation error.
		delete(v, "name")

		raw.rawConfig = v

		t.Builders[raw.Name] = raw
	}

	// Gather all the post-processors. This is a complicated process since there
	// are actually three different formats that the user can use to define
	// a post-processor.
	for i, rawV := range rawTpl.PostProcessors {
		rawPP, err := parsePostProvisioner(i, rawV)
		if err != nil {
			errors = append(errors, err...)
			continue
		}

		t.PostProcessors[i] = make([]RawPostProcessorConfig, len(rawPP))
		configs := t.PostProcessors[i]
		for j, pp := range rawPP {
			config := &configs[j]
			if err := mapstructure.Decode(pp, config); err != nil {
				if merr, ok := err.(*mapstructure.Error); ok {
					for _, err := range merr.Errors {
						errors = append(errors, fmt.Errorf("Post-processor #%d.%d: %s", i+1, j+1, err))
					}
				} else {
					errors = append(errors, fmt.Errorf("Post-processor %d.%d: %s", i+1, j+1, err))
				}

				continue
			}

			if config.Type == "" {
				errors = append(errors, fmt.Errorf("Post-processor %d.%d: missing 'type'", i+1, j+1))
				continue
			}

			config.rawConfig = pp
		}
	}

	// Gather all the provisioners
	for i, v := range rawTpl.Provisioners {
		raw := &t.Provisioners[i]
		if err := mapstructure.Decode(v, raw); err != nil {
			if merr, ok := err.(*mapstructure.Error); ok {
				for _, err := range merr.Errors {
					errors = append(errors, fmt.Errorf("provisioner %d: %s", i+1, err))
				}
			} else {
				errors = append(errors, fmt.Errorf("provisioner %d: %s", i+1, err))
			}

			continue
		}

		if raw.Type == "" {
			errors = append(errors, fmt.Errorf("provisioner %d: missing 'type'", i+1))
			continue
		}

		// The provisioners not only don't need or want the override settings
		// (as they are processed as part of the preparation below), but will
		// actively reject them as invalid configuration.
		delete(v, "override")

		raw.rawConfig = v
	}

	if len(t.Builders) == 0 {
		errors = append(errors, fmt.Errorf("No builders are defined in the template."))
	}

	// If there were errors, we put it into a MultiError and return
	if len(errors) > 0 {
		err = &MultiError{errors}
		t = nil
		return
	}

	return
}

// ParseTemplateFile takes the given template file and parses it into
// a single template.
func ParseTemplateFile(path string) (*Template, error) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, err
	}

	return ParseTemplate(data)
}

func parsePostProvisioner(i int, rawV interface{}) (result []map[string]interface{}, errors []error) {
	switch v := rawV.(type) {
	case string:
		result = []map[string]interface{}{
			{"type": v},
		}
	case map[string]interface{}:
		result = []map[string]interface{}{v}
	case []interface{}:
		result = make([]map[string]interface{}, len(v))
		errors = make([]error, 0)
		for j, innerRawV := range v {
			switch innerV := innerRawV.(type) {
			case string:
				result[j] = map[string]interface{}{"type": innerV}
			case map[string]interface{}:
				result[j] = innerV
			case []interface{}:
				errors = append(
					errors,
					fmt.Errorf("Post-processor %d.%d: sequences not allowed to be nested in sequences", i+1, j+1))
			default:
				errors = append(errors, fmt.Errorf("Post-processor %d.%d is in a bad format.", i+1, j+1))
			}
		}

		if len(errors) == 0 {
			errors = nil
		}
	default:
		result = nil
		errors = []error{fmt.Errorf("Post-processor %d is in a bad format.", i+1)}
	}

	return
}

// BuildNames returns a slice of the available names of builds that
// this template represents.
func (t *Template) BuildNames() []string {
	names := make([]string, 0, len(t.Builders))
	for name, _ := range t.Builders {
		names = append(names, name)
	}

	return names
}

// Build returns a Build for the given name.
//
// If the build does not exist as part of this template, an error is
// returned.
func (t *Template) Build(name string, components *ComponentFinder) (b Build, err error) {
	// Setup the Builder
	builderConfig, ok := t.Builders[name]
	if !ok {
		err = fmt.Errorf("No such build found in template: %s", name)
		return
	}

	// We panic if there is no builder function because this is really
	// an internal bug that always needs to be fixed, not an error.
	if components.Builder == nil {
		panic("no builder function")
	}

	// Panic if there are provisioners on the template but no provisioner
	// component finder. This is always an internal error, so we panic.
	if len(t.Provisioners) > 0 && components.Provisioner == nil {
		panic("no provisioner function")
	}

	builder, err := components.Builder(builderConfig.Type)
	if err != nil {
		return
	}

	if builder == nil {
		err = fmt.Errorf("Builder type not found: %s", builderConfig.Type)
		return
	}

	// Gather the Hooks
	hooks := make(map[string][]Hook)
	for tplEvent, tplHooks := range t.Hooks {
		curHooks := make([]Hook, 0, len(tplHooks))

		for _, hookName := range tplHooks {
			var hook Hook
			hook, err = components.Hook(hookName)
			if err != nil {
				return
			}

			if hook == nil {
				err = fmt.Errorf("Hook not found: %s", hookName)
				return
			}

			curHooks = append(curHooks, hook)
		}

		hooks[tplEvent] = curHooks
	}

	// Prepare the post-processors
	postProcessors := make([][]coreBuildPostProcessor, 0, len(t.PostProcessors))
	for _, rawPPs := range t.PostProcessors {
		current := make([]coreBuildPostProcessor, len(rawPPs))
		for i, rawPP := range rawPPs {
			pp, err := components.PostProcessor(rawPP.Type)
			if err != nil {
				return nil, err
			}

			if pp == nil {
				return nil, fmt.Errorf("PostProcessor type not found: %s", rawPP.Type)
			}

			current[i] = coreBuildPostProcessor{
				processor:         pp,
				processorType:     rawPP.Type,
				config:            rawPP.rawConfig,
				keepInputArtifact: rawPP.KeepInputArtifact,
			}
		}

		postProcessors = append(postProcessors, current)
	}

	// Prepare the provisioners
	provisioners := make([]coreBuildProvisioner, 0, len(t.Provisioners))
	for _, rawProvisioner := range t.Provisioners {
		var provisioner Provisioner
		provisioner, err = components.Provisioner(rawProvisioner.Type)
		if err != nil {
			return
		}

		if provisioner == nil {
			err = fmt.Errorf("Provisioner type not found: %s", rawProvisioner.Type)
			return
		}

		configs := make([]interface{}, 1, 2)
		configs[0] = rawProvisioner.rawConfig

		if rawProvisioner.Override != nil {
			if override, ok := rawProvisioner.Override[name]; ok {
				configs = append(configs, override)
			}
		}

		coreProv := coreBuildProvisioner{provisioner, configs}
		provisioners = append(provisioners, coreProv)
	}

	b = &coreBuild{
		name:           name,
		builder:        builder,
		builderConfig:  builderConfig.rawConfig,
		builderType:    builderConfig.Type,
		hooks:          hooks,
		postProcessors: postProcessors,
		provisioners:   provisioners,
		variables:      t.Variables,
	}

	return
}
<|endoftext|>


<commit_before>package skiplist

import (
	"math/rand"
	"sync/atomic"
	"unsafe"
)

const MaxLevel = 32
const p = 0.25

type CompareFn func(unsafe.Pointer, unsafe.Pointer) int
type ItemSizeFn func(unsafe.Pointer) int

func defaultItemSize(unsafe.Pointer) int {
	return 0
}

type Skiplist struct {
	head      *Node
	tail      *Node
	level     int32
	stats     stats
	usedBytes int64

	itemSize ItemSizeFn
}

func New() *Skiplist {
	head := newNode(nil, MaxLevel)
	tail := newNode(nil, MaxLevel)

	for i := 0; i <= MaxLevel; i++ {
		head.setNext(i, tail, false)
	}

	s := &Skiplist{
		head:     head,
		tail:     tail,
		itemSize: defaultItemSize,
	}

	return s
}

type ActionBuffer struct {
	preds []*Node
	succs []*Node
}

func (s *Skiplist) SetItemSizeFunc(fn ItemSizeFn) {
	s.itemSize = fn
}

func (s *Skiplist) MakeBuf() *ActionBuffer {
	return &ActionBuffer{
		preds: make([]*Node, MaxLevel+1),
		succs: make([]*Node, MaxLevel+1),
	}
}

// TODO: Use sync pool
func (s *Skiplist) FreeBuf(b *ActionBuffer) {
}

type Node struct {
	next   []unsafe.Pointer
	itm    unsafe.Pointer
	GClink *Node
}

func (n Node) Level() int {
	return int(len(n.next) - 1)
}

func (n *Node) Item() unsafe.Pointer {
	return n.itm
}

func (n *Node) SetLink(l *Node) {
	n.GClink = l
}

func (n *Node) GetLink() *Node {
	return n.GClink
}

type NodeRef struct {
	deleted bool
	ptr     *Node
}

func newNode(itm unsafe.Pointer, level int) *Node {
	n := &Node{
		next: make([]unsafe.Pointer, level+1),
	}

	n.itm = itm
	return n
}

func (n *Node) setNext(level int, ptr *Node, deleted bool) {
	n.next[level] = unsafe.Pointer(&NodeRef{ptr: ptr, deleted: deleted})
}

func (n *Node) getNext(level int) (*Node, bool) {
	ref := (*NodeRef)(atomic.LoadPointer(&n.next[level]))
	if ref != nil {
		return ref.ptr, ref.deleted
	}

	return nil, false
}

func (n *Node) dcasNext(level int, prevPtr, newPtr *Node, prevIsdeleted, newIsdeleted bool) bool {
	var swapped bool
	addr := &n.next[level]
	ref := (*NodeRef)(atomic.LoadPointer(addr))
	if ref != nil {
		if ref.ptr == prevPtr && ref.deleted == prevIsdeleted {
			swapped = atomic.CompareAndSwapPointer(addr, unsafe.Pointer(ref),
				unsafe.Pointer(&NodeRef{ptr: newPtr, deleted: newIsdeleted}))
		}
	}

	return swapped
}

func (s *Skiplist) Size(n *Node) int {
	var ref NodeRef
	var next *Node

	itmSz := uintptr(s.itemSize(n.Item()))

	return int(
		unsafe.Sizeof(n.next) +
			unsafe.Sizeof(n.itm) +
			itmSz +
			unsafe.Sizeof(n.GClink) +
			(unsafe.Sizeof(next)+unsafe.Sizeof(ref))*uintptr(n.Level()+1))
}

func (s *Skiplist) NewLevel(randFn func() float32) int {
	var nextLevel int

	for ; randFn() < p; nextLevel++ {
	}

	if nextLevel > MaxLevel {
		nextLevel = MaxLevel
	}

	level := int(atomic.LoadInt32(&s.level))
	if nextLevel > level {
		if atomic.CompareAndSwapInt32(&s.level, int32(level), int32(level+1)) {
			nextLevel = level + 1
		} else {
			nextLevel = level
		}
	}

	return nextLevel
}

func (s *Skiplist) helpDelete(level int, prev, curr, next *Node) bool {
	success := prev.dcasNext(level, curr, next, false, false)
	if success && level == curr.Level() {
		atomic.AddInt64(&s.stats.softDeletes, -1)
		atomic.AddInt64(&s.stats.levelNodesCount[level], -1)
		atomic.AddInt64(&s.usedBytes, -int64(s.Size(curr)))
	}
	return success
}

func (s *Skiplist) FindPath(itm unsafe.Pointer, cmp CompareFn,
	buf *ActionBuffer) (foundNode *Node) {
	var cmpVal int = 1

retry:
	prev := s.head
	level := int(atomic.LoadInt32(&s.level))
	for i := level; i >= 0; i-- {
		curr, _ := prev.getNext(i)
	levelSearch:
		for {
			next, deleted := curr.getNext(i)
			for deleted {
				if !s.helpDelete(i, prev, curr, next) {
					atomic.AddUint64(&s.stats.readConflicts, 1)
					goto retry
				}

				curr, _ = prev.getNext(i)
				next, deleted = curr.getNext(i)
			}

			cmpVal = compare(cmp, curr.Item(), itm)
			if cmpVal < 0 {
				prev = curr
				curr, _ = prev.getNext(i)
			} else {
				break levelSearch
			}
		}

		buf.preds[i] = prev
		buf.succs[i] = curr
	}

	if cmpVal == 0 {
		foundNode = buf.succs[0]
	}
	return
}

func (s *Skiplist) Insert(itm unsafe.Pointer, cmp CompareFn, buf *ActionBuffer) (success bool) {
	_, success = s.Insert2(itm, cmp, buf, rand.Float32)
	return
}

func (s *Skiplist) Insert2(itm unsafe.Pointer, cmp CompareFn,
	buf *ActionBuffer, randFn func() float32) (*Node, bool) {
	itemLevel := s.NewLevel(randFn)
	return s.Insert3(itm, cmp, buf, itemLevel, false)
}

func (s *Skiplist) Insert3(itm unsafe.Pointer, cmp CompareFn,
	buf *ActionBuffer, itemLevel int, skipFindPath bool) (*Node, bool) {

	x := newNode(itm, itemLevel)
	atomic.AddInt64(&s.stats.levelNodesCount[itemLevel], 1)
	atomic.AddInt64(&s.usedBytes, int64(s.Size(x)))

retry:
	if skipFindPath {
		skipFindPath = false
	} else {
		if s.FindPath(itm, cmp, buf) != nil {
			return nil, false
		}
	}

	x.setNext(0, buf.succs[0], false)
	if !buf.preds[0].dcasNext(0, buf.succs[0], x, false, false) {
		atomic.AddUint64(&s.stats.insertConflicts, 1)
		goto retry
	}

	for i := 1; i <= int(itemLevel); i++ {
	fixThisLevel:
		for {
			x.setNext(i, buf.succs[i], false)
			if buf.preds[i].dcasNext(i, buf.succs[i], x, false, false) {
				break fixThisLevel
			}
			s.FindPath(itm, cmp, buf)
		}
	}

	return x, true
}

func (s *Skiplist) softDelete(delNode *Node) bool {
	var deleteMarked bool

	targetLevel := delNode.Level()
	for i := targetLevel; i >= 0; i-- {
		next, deleted := delNode.getNext(i)
		for !deleted {
			deleteMarked = delNode.dcasNext(i, next, next, false, true)
			next, deleted = delNode.getNext(i)
		}
	}

	if deleteMarked {
		atomic.AddInt64(&s.stats.softDeletes, 1)
	}

	return deleteMarked
}

func (s *Skiplist) Delete(itm unsafe.Pointer, cmp CompareFn, buf *ActionBuffer) bool {
	found := s.FindPath(itm, cmp, buf) != nil
	if !found {
		return false
	}

	delNode := buf.succs[0]
	return s.DeleteNode(delNode, cmp, buf)
}

func (s *Skiplist) DeleteNode(n *Node, cmp CompareFn, buf *ActionBuffer) bool {
	itm := n.Item()
	if s.softDelete(n) {
		s.FindPath(itm, cmp, buf)
		return true
	}

	return false
}

func (s *Skiplist) GetRangeSplitItems(nways int) []unsafe.Pointer {
	var deleted bool
repeat:
	var itms []unsafe.Pointer
	var finished bool

	l := int(atomic.LoadInt32(&s.level))
	for ; l >= 0; l-- {
		c := int(atomic.LoadInt64(&s.stats.levelNodesCount[l]) + 1)
		if c >= nways {
			perSplit := c / nways
			node := s.head
			for j := 0; node != s.tail && !finished; j++ {
				if j == perSplit {
					j = -1
					itms = append(itms, node.Item())
					finished = len(itms) == nways-1
				}

				node, deleted = node.getNext(l)
				if deleted {
					goto repeat
				}
			}

			break
		}
	}

	return itms
}
<commit_msg>skiplist: Reduce next[] pointer slice overhead by 8 bytes<commit_after>package skiplist

import (
	"math/rand"
	"reflect"
	"sync/atomic"
	"unsafe"
)

const MaxLevel = 32
const p = 0.25

type CompareFn func(unsafe.Pointer, unsafe.Pointer) int
type ItemSizeFn func(unsafe.Pointer) int

func defaultItemSize(unsafe.Pointer) int {
	return 0
}

type Skiplist struct {
	head      *Node
	tail      *Node
	level     int32
	stats     stats
	usedBytes int64

	itemSize ItemSizeFn
}

func New() *Skiplist {
	head := newNode(nil, MaxLevel)
	tail := newNode(nil, MaxLevel)

	for i := 0; i <= MaxLevel; i++ {
		head.setNext(i, tail, false)
	}

	s := &Skiplist{
		head:     head,
		tail:     tail,
		itemSize: defaultItemSize,
	}

	return s
}

type ActionBuffer struct {
	preds []*Node
	succs []*Node
}

func (s *Skiplist) SetItemSizeFunc(fn ItemSizeFn) {
	s.itemSize = fn
}

func (s *Skiplist) MakeBuf() *ActionBuffer {
	return &ActionBuffer{
		preds: make([]*Node, MaxLevel+1),
		succs: make([]*Node, MaxLevel+1),
	}
}

// TODO: Use sync pool
func (s *Skiplist) FreeBuf(b *ActionBuffer) {
}

type Node struct {
	level  int
	next   unsafe.Pointer // Points to [level+1]unsafe.Pointer
	itm    unsafe.Pointer
	GClink *Node
}

func (n *Node) nextArray() (s []unsafe.Pointer) {
	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&s))
	hdr.Data = uintptr(n.next)
	hdr.Len = n.Level() + 1
	hdr.Cap = hdr.Len
	return
}

func (n Node) Level() int {
	return int(n.level)
}

func (n *Node) Item() unsafe.Pointer {
	return n.itm
}

func (n *Node) SetLink(l *Node) {
	n.GClink = l
}

func (n *Node) GetLink() *Node {
	return n.GClink
}

type NodeRef struct {
	deleted bool
	ptr     *Node
}

func newNode(itm unsafe.Pointer, level int) *Node {
	next := make([]unsafe.Pointer, level+1)
	n := &Node{
		level: level,
		next:  unsafe.Pointer(&next[0]),
	}

	n.itm = itm
	return n
}

func (n *Node) setNext(level int, ptr *Node, deleted bool) {
	next := n.nextArray()
	next[level] = unsafe.Pointer(&NodeRef{ptr: ptr, deleted: deleted})
}

func (n *Node) getNext(level int) (*Node, bool) {
	next := n.nextArray()
	ref := (*NodeRef)(atomic.LoadPointer(&next[level]))
	if ref != nil {
		return ref.ptr, ref.deleted
	}

	return nil, false
}

func (n *Node) dcasNext(level int, prevPtr, newPtr *Node, prevIsdeleted, newIsdeleted bool) bool {
	var swapped bool

	next := n.nextArray()
	addr := &next[level]
	ref := (*NodeRef)(atomic.LoadPointer(addr))
	if ref != nil {
		if ref.ptr == prevPtr && ref.deleted == prevIsdeleted {
			swapped = atomic.CompareAndSwapPointer(addr, unsafe.Pointer(ref),
				unsafe.Pointer(&NodeRef{ptr: newPtr, deleted: newIsdeleted}))
		}
	}

	return swapped
}

func (s *Skiplist) Size(n *Node) int {
	var ref NodeRef
	var next *Node

	itmSz := uintptr(s.itemSize(n.Item()))

	return int(
		unsafe.Sizeof(n.next) +
			unsafe.Sizeof(n.itm) +
			itmSz +
			unsafe.Sizeof(n.GClink) +
			(unsafe.Sizeof(next)+unsafe.Sizeof(ref))*uintptr(n.Level()+1))
}

func (s *Skiplist) NewLevel(randFn func() float32) int {
	var nextLevel int

	for ; randFn() < p; nextLevel++ {
	}

	if nextLevel > MaxLevel {
		nextLevel = MaxLevel
	}

	level := int(atomic.LoadInt32(&s.level))
	if nextLevel > level {
		if atomic.CompareAndSwapInt32(&s.level, int32(level), int32(level+1)) {
			nextLevel = level + 1
		} else {
			nextLevel = level
		}
	}

	return nextLevel
}

func (s *Skiplist) helpDelete(level int, prev, curr, next *Node) bool {
	success := prev.dcasNext(level, curr, next, false, false)
	if success && level == curr.Level() {
		atomic.AddInt64(&s.stats.softDeletes, -1)
		atomic.AddInt64(&s.stats.levelNodesCount[level], -1)
		atomic.AddInt64(&s.usedBytes, -int64(s.Size(curr)))
	}
	return success
}

func (s *Skiplist) FindPath(itm unsafe.Pointer, cmp CompareFn,
	buf *ActionBuffer) (foundNode *Node) {
	var cmpVal int = 1

retry:
	prev := s.head
	level := int(atomic.LoadInt32(&s.level))
	for i := level; i >= 0; i-- {
		curr, _ := prev.getNext(i)
	levelSearch:
		for {
			next, deleted := curr.getNext(i)
			for deleted {
				if !s.helpDelete(i, prev, curr, next) {
					atomic.AddUint64(&s.stats.readConflicts, 1)
					goto retry
				}

				curr, _ = prev.getNext(i)
				next, deleted = curr.getNext(i)
			}

			cmpVal = compare(cmp, curr.Item(), itm)
			if cmpVal < 0 {
				prev = curr
				curr, _ = prev.getNext(i)
			} else {
				break levelSearch
			}
		}

		buf.preds[i] = prev
		buf.succs[i] = curr
	}

	if cmpVal == 0 {
		foundNode = buf.succs[0]
	}
	return
}

func (s *Skiplist) Insert(itm unsafe.Pointer, cmp CompareFn, buf *ActionBuffer) (success bool) {
	_, success = s.Insert2(itm, cmp, buf, rand.Float32)
	return
}

func (s *Skiplist) Insert2(itm unsafe.Pointer, cmp CompareFn,
	buf *ActionBuffer, randFn func() float32) (*Node, bool) {
	itemLevel := s.NewLevel(randFn)
	return s.Insert3(itm, cmp, buf, itemLevel, false)
}

func (s *Skiplist) Insert3(itm unsafe.Pointer, cmp CompareFn,
	buf *ActionBuffer, itemLevel int, skipFindPath bool) (*Node, bool) {

	x := newNode(itm, itemLevel)
	atomic.AddInt64(&s.stats.levelNodesCount[itemLevel], 1)
	atomic.AddInt64(&s.usedBytes, int64(s.Size(x)))

retry:
	if skipFindPath {
		skipFindPath = false
	} else {
		if s.FindPath(itm, cmp, buf) != nil {
			return nil, false
		}
	}

	x.setNext(0, buf.succs[0], false)
	if !buf.preds[0].dcasNext(0, buf.succs[0], x, false, false) {
		atomic.AddUint64(&s.stats.insertConflicts, 1)
		goto retry
	}

	for i := 1; i <= int(itemLevel); i++ {
	fixThisLevel:
		for {
			x.setNext(i, buf.succs[i], false)
			if buf.preds[i].dcasNext(i, buf.succs[i], x, false, false) {
				break fixThisLevel
			}
			s.FindPath(itm, cmp, buf)
		}
	}

	return x, true
}

func (s *Skiplist) softDelete(delNode *Node) bool {
	var deleteMarked bool

	targetLevel := delNode.Level()
	for i := targetLevel; i >= 0; i-- {
		next, deleted := delNode.getNext(i)
		for !deleted {
			deleteMarked = delNode.dcasNext(i, next, next, false, true)
			next, deleted = delNode.getNext(i)
		}
	}

	if deleteMarked {
		atomic.AddInt64(&s.stats.softDeletes, 1)
	}

	return deleteMarked
}

func (s *Skiplist) Delete(itm unsafe.Pointer, cmp CompareFn, buf *ActionBuffer) bool {
	found := s.FindPath(itm, cmp, buf) != nil
	if !found {
		return false
	}

	delNode := buf.succs[0]
	return s.DeleteNode(delNode, cmp, buf)
}

func (s *Skiplist) DeleteNode(n *Node, cmp CompareFn, buf *ActionBuffer) bool {
	itm := n.Item()
	if s.softDelete(n) {
		s.FindPath(itm, cmp, buf)
		return true
	}

	return false
}

func (s *Skiplist) GetRangeSplitItems(nways int) []unsafe.Pointer {
	var deleted bool
repeat:
	var itms []unsafe.Pointer
	var finished bool

	l := int(atomic.LoadInt32(&s.level))
	for ; l >= 0; l-- {
		c := int(atomic.LoadInt64(&s.stats.levelNodesCount[l]) + 1)
		if c >= nways {
			perSplit := c / nways
			node := s.head
			for j := 0; node != s.tail && !finished; j++ {
				if j == perSplit {
					j = -1
					itms = append(itms, node.Item())
					finished = len(itms) == nways-1
				}

				node, deleted = node.getNext(l)
				if deleted {
					goto repeat
				}
			}

			break
		}
	}

	return itms
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gles

import (
	"context"

	"github.com/google/gapid/core/os/device"
	"github.com/google/gapid/gapis/api"
	"github.com/google/gapid/gapis/api/transform"
	"github.com/google/gapid/gapis/memory"
)

// undefinedFramebuffer adds a transform that will render a pattern into the
// color buffer at the end of each frame.
func undefinedFramebuffer(ctx context.Context, device *device.Instance) transform.Transformer {
	seenSurfaces := make(map[EGLSurface]bool)
	return transform.Transform("DirtyFramebuffer", func(ctx context.Context, id api.CmdID, cmd api.Cmd, out transform.Writer) {
		out.MutateAndWrite(ctx, id, cmd)
		s := out.State()
		c := GetContext(s, cmd.Thread())
		if c == nil || !c.Other.Initialized {
			return // We can't do anything without a context.
		}
		if eglMakeCurrent, ok := cmd.(*EglMakeCurrent); ok && !seenSurfaces[eglMakeCurrent.Draw] {
			// Render the undefined pattern for new contexts.
			drawUndefinedFramebuffer(ctx, id, cmd, device, s, c, out)
			seenSurfaces[eglMakeCurrent.Draw] = true
		}
		if cmd.CmdFlags(ctx, id, s).IsStartOfFrame() {
			if _, ok := cmd.(*EglSwapBuffersWithDamageKHR); ok {
				// TODO: This is a hack. eglSwapBuffersWithDamageKHR is nearly
				// exculsively used by the Android framework, which also loves
				// to do partial framebuffer updates. Unfortunately we do not
				// currently know whether the framebuffer is invalidated between
				// calls to eglSwapBuffersWithDamageKHR as the OS now uses the
				// EGL_EXT_buffer_age extension, which we do not track. For now,
				// assume that eglSwapBuffersWithDamageKHR calls are coming from
				// the framework, and that the framebuffer is reused between
				// calls.
				// BUG: https://github.com/google/gapid/issues/846.
				return
			}
			if c != nil && !c.Other.PreserveBuffersOnSwap {
				drawUndefinedFramebuffer(ctx, id, cmd, device, s, c, out)
			}
		}
	})
}

func drawUndefinedFramebuffer(ctx context.Context, id api.CmdID, cmd api.Cmd, device *device.Instance, s *api.GlobalState, c *Context, out transform.Writer) error {
	const (
		aScreenCoordsLocation AttributeLocation = 0

		vertexShaderSource string = `
					precision highp float;
					attribute vec2 aScreenCoords;
					varying vec2 uv;

					void main() {
						uv = aScreenCoords;
						gl_Position = vec4(aScreenCoords.xy, 0., 1.);
					}`
		fragmentShaderSource string = `
					precision highp float;
					varying vec2 uv;

					float F(float a) { return smoothstep(0.0, 0.1, a) * smoothstep(0.4, 0.3, a); }

					void main() {
						vec2 v = uv * 5.0;
						gl_FragColor = vec4(0.8, 0.9, 0.6, 1.0) * F(fract(v.x + v.y));
					}`
	)

	// 2D vertices positions for a full screen 2D triangle strip.
	positions := []float32{-1., -1., 1., -1., -1., 1., 1., 1.}

	dID := id.Derived()
	cb := CommandBuilder{Thread: cmd.Thread()}
	t := newTweaker(out, id, cb)

	// Temporarily change rasterizing/blending state and enable VAP 0.
	t.glDisable(ctx, GLenum_GL_BLEND)
	t.glDisable(ctx, GLenum_GL_CULL_FACE)
	t.glDisable(ctx, GLenum_GL_DEPTH_TEST)
	t.glDisable(ctx, GLenum_GL_SCISSOR_TEST)
	t.glDisable(ctx, GLenum_GL_STENCIL_TEST)
	t.makeVertexArray(ctx, aScreenCoordsLocation)

	programID := t.makeProgram(ctx, vertexShaderSource, fragmentShaderSource)

	tmp0 := t.AllocData(ctx, "aScreenCoords")
	out.MutateAndWrite(ctx, dID, cb.GlBindAttribLocation(programID, aScreenCoordsLocation, tmp0.Ptr()).
		AddRead(tmp0.Data()))
	tmp0.Free()
	out.MutateAndWrite(ctx, dID, api.WithExtras(cb.GlLinkProgram(programID), &LinkProgramExtra{
		LinkStatus:      GLboolean_GL_TRUE,
		ActiveResources: &ActiveProgramResources{},
	}))
	t.glUseProgram(ctx, programID)

	bufferID := t.glGenBuffer(ctx)
	t.GlBindBuffer_ArrayBuffer(ctx, bufferID)

	tmp1 := t.AllocData(ctx, positions)
	out.MutateAndWrite(ctx, dID, cb.GlBufferData(GLenum_GL_ARRAY_BUFFER, GLsizeiptr(4*len(positions)), tmp1.Ptr(), GLenum_GL_STATIC_DRAW).
		AddRead(tmp1.Data()))
	tmp1.Free()

	out.MutateAndWrite(ctx, dID, cb.GlVertexAttribPointer(aScreenCoordsLocation, 2, GLenum_GL_FLOAT, GLboolean(0), 0, memory.Nullptr))
	out.MutateAndWrite(ctx, dID, cb.GlDrawArrays(GLenum_GL_TRIANGLE_STRIP, 0, 4))

	t.revert(ctx)

	return nil
}
<commit_msg>gles: Fix the rendering of undefined framebuffer patterns<commit_after>// Copyright (C) 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gles

import (
	"context"

	"github.com/google/gapid/core/os/device"
	"github.com/google/gapid/gapis/api"
	"github.com/google/gapid/gapis/api/transform"
	"github.com/google/gapid/gapis/memory"
)

// undefinedFramebuffer adds a transform that will render a pattern into the
// color buffer at the end of each frame.
func undefinedFramebuffer(ctx context.Context, device *device.Instance) transform.Transformer {
	seenSurfaces := make(map[EGLSurface]bool)
	return transform.Transform("DirtyFramebuffer", func(ctx context.Context, id api.CmdID, cmd api.Cmd, out transform.Writer) {
		out.MutateAndWrite(ctx, id, cmd)
		s := out.State()
		c := GetContext(s, cmd.Thread())
		if c == nil || !c.Other.Initialized {
			return // We can't do anything without a context.
		}
		if eglMakeCurrent, ok := cmd.(*EglMakeCurrent); ok && !seenSurfaces[eglMakeCurrent.Draw] {
			// Render the undefined pattern for new contexts.
			drawUndefinedFramebuffer(ctx, id, cmd, device, s, c, out)
			seenSurfaces[eglMakeCurrent.Draw] = true
		}
		if cmd.CmdFlags(ctx, id, s).IsStartOfFrame() {
			if _, ok := cmd.(*EglSwapBuffersWithDamageKHR); ok {
				// TODO: This is a hack. eglSwapBuffersWithDamageKHR is nearly
				// exculsively used by the Android framework, which also loves
				// to do partial framebuffer updates. Unfortunately we do not
				// currently know whether the framebuffer is invalidated between
				// calls to eglSwapBuffersWithDamageKHR as the OS now uses the
				// EGL_EXT_buffer_age extension, which we do not track. For now,
				// assume that eglSwapBuffersWithDamageKHR calls are coming from
				// the framework, and that the framebuffer is reused between
				// calls.
				// BUG: https://github.com/google/gapid/issues/846.
				return
			}
			if c != nil && !c.Other.PreserveBuffersOnSwap {
				drawUndefinedFramebuffer(ctx, id, cmd, device, s, c, out)
			}
		}
	})
}

func drawUndefinedFramebuffer(ctx context.Context, id api.CmdID, cmd api.Cmd, device *device.Instance, s *api.GlobalState, c *Context, out transform.Writer) error {
	const (
		aScreenCoordsLocation AttributeLocation = 0
		aScreenCoords                           = "aScreenCoords"

		vertexShaderSource string = `
					#version 100

					precision highp float;
					attribute vec2 aScreenCoords;
					varying vec2 uv;

					void main() {
						uv = aScreenCoords;
						gl_Position = vec4(aScreenCoords.xy, 0., 1.);
					}`
		fragmentShaderSource string = `
					#version 100

					precision highp float;
					varying vec2 uv;

					float F(float a) { return smoothstep(0.0, 0.1, a) * smoothstep(0.4, 0.3, a); }

					void main() {
						vec2 v = uv * 5.0;
						gl_FragColor = vec4(0.8, 0.9, 0.6, 1.0) * F(fract(v.x + v.y));
					}`
	)

	// 2D vertices positions for a full screen 2D triangle strip.
	positions := []float32{-1., -1., 1., -1., -1., 1., 1., 1.}

	dID := id.Derived()
	cb := CommandBuilder{Thread: cmd.Thread()}
	t := newTweaker(out, id, cb)

	// Temporarily change rasterizing/blending state and enable VAP 0.
	t.glDisable(ctx, GLenum_GL_BLEND)
	t.glDisable(ctx, GLenum_GL_CULL_FACE)
	t.glDisable(ctx, GLenum_GL_DEPTH_TEST)
	t.glDisable(ctx, GLenum_GL_SCISSOR_TEST)
	t.glDisable(ctx, GLenum_GL_STENCIL_TEST)
	t.makeVertexArray(ctx, aScreenCoordsLocation)

	programID := t.makeProgram(ctx, vertexShaderSource, fragmentShaderSource)

	tmp0 := t.AllocData(ctx, aScreenCoords)
	out.MutateAndWrite(ctx, dID, cb.GlBindAttribLocation(programID, aScreenCoordsLocation, tmp0.Ptr()).
		AddRead(tmp0.Data()))
	tmp0.Free()
	out.MutateAndWrite(ctx, dID, api.WithExtras(cb.GlLinkProgram(programID), &LinkProgramExtra{
		LinkStatus: GLboolean_GL_TRUE,
		ActiveResources: &ActiveProgramResources{
			ProgramInputs: NewU32ːProgramResourceʳᵐ().Add(0, &ProgramResource{
				Type:      GLenum_GL_FLOAT_VEC2,
				Name:      aScreenCoords,
				ArraySize: 1,
				Locations: NewU32ːGLintᵐ().Add(0, 0),
			}),
		},
	}))
	t.glUseProgram(ctx, programID)

	bufferID := t.glGenBuffer(ctx)
	t.GlBindBuffer_ArrayBuffer(ctx, bufferID)

	tmp1 := t.AllocData(ctx, positions)
	out.MutateAndWrite(ctx, dID, cb.GlBufferData(GLenum_GL_ARRAY_BUFFER, GLsizeiptr(4*len(positions)), tmp1.Ptr(), GLenum_GL_STATIC_DRAW).
		AddRead(tmp1.Data()))
	tmp1.Free()

	out.MutateAndWrite(ctx, dID, cb.GlVertexAttribPointer(aScreenCoordsLocation, 2, GLenum_GL_FLOAT, GLboolean(0), 0, memory.Nullptr))
	out.MutateAndWrite(ctx, dID, cb.GlDrawArrays(GLenum_GL_TRIANGLE_STRIP, 0, 4))

	t.revert(ctx)

	return nil
}
<|endoftext|>


<commit_before>package apigateway

import (
	"errors"
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/apigateway"
	"github.com/aws/aws-sdk-go/service/lambda"
	"strings"
)

//SetupRestAPIInput represent a request to setup API with specified resources
type SetupRestAPIInput struct {
	apigateway.CreateRestApiInput    ` json:",inline"`
	Resources                        []*SetupResourceInput
	apigateway.CreateDeploymentInput ` json:",inline"`
	Redeploy                         bool
}

//SetupRestAPIInput represent setup API response
type SetupRestAPIOutput struct {
	*apigateway.RestApi
	Resources   []*SetupResourceOutput
	Stage       *apigateway.Stage
	EndpointURL string
	Region      string
}

//SetupResourceInput represents resource input
type SetupResourceInput struct {
	Path                           string
	apigateway.CreateResourceInput `json:",inline"`
	Methods                        []*ResourceMethod
}

//ResourceMethod represents resource method
type ResourceMethod struct {
	FunctionName string
	HttpMethod   string
	*apigateway.PutMethodInput
	*apigateway.PutIntegrationInput
	*lambda.AddPermissionInput
}

//SetupResourceOutput represents setup resource output
type SetupResourceOutput struct {
	*apigateway.Resource `json:",inline"`
	ResourceMethods      map[string]*apigateway.Method
}

//RemoveRestAPI removes API for supplied name
type RemoveRestAPIInput struct {
	Name *string
}

func (i *RemoveRestAPIInput) Validate() error {
	if i.Name == nil {
		return errors.New("name was empty")
	}
	return nil
}

func (i *SetupRestAPIInput) Init() error {
	if len(i.Resources) == 0 {
		return nil
	}

	var URIs = make(map[string]bool)
	var resources = make([]*SetupResourceInput, 0)

	for _, resource := range i.Resources {
		if err := resource.Init(); err != nil {
			return err
		}
		URIs[resource.Path] = true

		parts := strings.Split(resource.Path, "/")

		for i := 1; i < len(parts)-1; i++ {
			ancestor := strings.Join(parts[0:i+1], "/")
			if URIs[ancestor] {
				continue
			}
			ancestorResource := &SetupResourceInput{Path: ancestor}
			_ = ancestorResource.Init()
			resources = append(resources, ancestorResource)
		}
		resources = append(resources, resource)
	}
	i.Resources = resources
	return nil
}

//Validate checks is input is valud
func (i *SetupRestAPIInput) Validate() error {
	if len(i.Resources) == 0 {
		return fmt.Errorf("resources was empty")
	}
	for _, resource := range i.Resources {
		if err := resource.Validate(); err != nil {
			return err
		}
	}
	createDeployment := &i.CreateDeploymentInput
	if createDeployment.StageName == nil {
		createDeployment.StageName = aws.String("e2e")
	}
	return nil
}

//Init initialize input
func (i *SetupResourceInput) Init() error {
	if i.Path == "" {
		if i.PathPart != nil {
			i.Path = "/" + *i.PathPart
		} else {
			i.Path = "/"
		}
	}
	if i.PathPart == nil {
		parts := strings.Split(i.Path, "/")
		if len(parts) > 1 {
			i.PathPart = &parts[len(parts)-1]
		}
	}
	if len(i.Methods) == 0 {
		return nil
	}
	for _, method := range i.Methods {
		if err := method.Init(); err != nil {
			return err
		}
	}
	return nil
}

func (i *SetupResourceInput) Validate() error {
	resourceInput := i.CreateResourceInput
	if resourceInput.PathPart == nil {
		return fmt.Errorf("pathPart was empty")
	}
	if len(i.Methods) > 0 {
		for _, method := range i.Methods {
			if err := method.Validate(); err != nil {
				return err
			}
		}
	}
	return nil
}

//ParentPath returns parent path
func (i *SetupResourceInput) ParentPath() string {
	if i.PathPart == nil {
		return i.Path
	}
	index := strings.LastIndex(i.Path, *i.PathPart)
	if index == -1 {
		return i.Path
	}
	result := string(i.Path[:index])
	if result == "/" {
		return result
	}
	if strings.HasSuffix(result, "/") {
		return string(result[:len(result)-1])
	}
	return result
}

/*
	Initialise resource with the following defaults

AuthorizationType: NONE

HttpMethod: ANY

ApiKeyRequired: false

IntegrationHttpMethod: POST

DetailType: AWS_PROXY

Uri: arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/${function.arn}/invocations

	It supports data substitution on uri attribute i.e.
	- 	$function.arn
	-	$function.region
	-	$function.accountID
	-	$restAPI.ID
	-	$uuid.next

*/
func (i *ResourceMethod) Init() error {

	methodInput := i.PutMethodInput
	if methodInput == nil {
		i.PutMethodInput = &apigateway.PutMethodInput{}
		methodInput = i.PutMethodInput
	}
	if methodInput != nil {
		methodInput.AuthorizationType = aws.String("NONE")
	}

	if methodInput.ApiKeyRequired == nil {
		methodInput.ApiKeyRequired = aws.Bool(false)
	}
	integrationInput := i.PutIntegrationInput
	if integrationInput == nil {
		i.PutIntegrationInput = &apigateway.PutIntegrationInput{}
		integrationInput = i.PutIntegrationInput
	}

	if i.HttpMethod != "" {
		methodInput.HttpMethod = &i.HttpMethod
		integrationInput.HttpMethod = &i.HttpMethod
	}

	if integrationInput.HttpMethod == nil {
		integrationInput.HttpMethod = methodInput.HttpMethod
	}
	if integrationInput.IntegrationHttpMethod == nil {
		integrationInput.IntegrationHttpMethod = aws.String("POST")
	}

	if i.FunctionName != "" {
		if integrationInput.Type == nil {
			integrationInput.Type = aws.String("AWS_PROXY")
		}

		if integrationInput.Uri == nil {
			integrationInput.Uri = aws.String("arn:aws:apigateway:${function.region}:lambda:path/2015-03-31/functions/${function.arn}/invocations")
		}
		permissionInput := i.AddPermissionInput
		if i.AddPermissionInput == nil {
			i.AddPermissionInput = &lambda.AddPermissionInput{}
			permissionInput = i.AddPermissionInput
		}
		if permissionInput.FunctionName == nil {
			permissionInput.FunctionName = &i.FunctionName
		}
		if permissionInput.Action == nil {
			permissionInput.Action = aws.String("lambda:InvokeFunction")
		}
		if permissionInput.Principal == nil {
			permissionInput.Principal = aws.String("apigateway.amazonaws.com")
		}
		if permissionInput.StatementId == nil {
			permissionInput.StatementId = aws.String("${uuid.next}")
		}
		if permissionInput.SourceArn == nil {
			permissionInput.SourceArn = aws.String("arn:aws:execute-api:${function.region}:${function.accountID}:${restAPI.ID}/*/*/*")
		}
	}
	return nil
}

func (i *ResourceMethod) Validate() error {
	if i.HttpMethod == "" {
		return fmt.Errorf("httpMethod was empty")
	}
	if i.Type == nil {
		return fmt.Errorf("type was empty")
	}
	return nil
}

//SetupMethodInput setups method input
type SetupMethodInput apigateway.PutMethodInput

//Diff computes patches
func (i SetupMethodInput) Diff(source *apigateway.Method) []*apigateway.PatchOperation {
	var result = make([]*apigateway.PatchOperation, 0)
	if patch, ok := patchBool(source.ApiKeyRequired, i.ApiKeyRequired, "/apiKeyRequired"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.AuthorizationType, i.AuthorizationType, "/authorizationType"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.AuthorizerId, i.AuthorizerId, "/authorizerId"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.OperationName, i.OperationName, "/operationName"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.RequestValidatorId, i.RequestValidatorId, "/requestValidatorId"); ok {
		result = append(result, patch)
	}
	return result
}

type PutIntegrationInput apigateway.PutIntegrationInput

//Diff computes patches
func (i PutIntegrationInput) Diff(source *apigateway.Integration) []*apigateway.PatchOperation {
	var result = make([]*apigateway.PatchOperation, 0)
	if patch, ok := patchString(source.Uri, i.Uri, "/uri"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.Credentials, i.Credentials, "/credentials"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.Type, i.Type, "/integrationType"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.ConnectionId, i.ConnectionId, "/connectionId"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.ConnectionType, i.ConnectionType, "/connectionType"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.ContentHandling, i.ContentHandling, "/contentHandling"); ok {
		result = append(result, patch)
	}
	if i.PassthroughBehavior != nil {
		if patch, ok := patchString(source.PassthroughBehavior, i.PassthroughBehavior, "/passthroughBehavior"); ok {
			result = append(result, patch)
		}
	}
	return result
}

type SetupDeploymentInput apigateway.CreateDeploymentInput

func (i *SetupDeploymentInput) Diff(source *apigateway.CreateDeploymentInput) []*apigateway.PatchOperation {
	var result = make([]*apigateway.PatchOperation, 0)
	if patch, ok := patchString(source.StageName, i.StageName, "/stageName"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.Description, i.Description, "/description"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.StageDescription, i.StageDescription, "/stageDescription"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchBool(source.CacheClusterEnabled, i.CacheClusterEnabled, "/cacheClusterEnabled"); ok {
		result = append(result, patch)
	}

	return result
}
<commit_msg>reverted typo<commit_after>package apigateway

import (
	"errors"
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/apigateway"
	"github.com/aws/aws-sdk-go/service/lambda"
	"strings"
)

//SetupRestAPIInput represent a request to setup API with specified resources
type SetupRestAPIInput struct {
	apigateway.CreateRestApiInput    ` json:",inline"`
	Resources                        []*SetupResourceInput
	apigateway.CreateDeploymentInput ` json:",inline"`
	Redeploy                         bool
}

//SetupRestAPIInput represent setup API response
type SetupRestAPIOutput struct {
	*apigateway.RestApi
	Resources   []*SetupResourceOutput
	Stage       *apigateway.Stage
	EndpointURL string
	Region      string
}

//SetupResourceInput represents resource input
type SetupResourceInput struct {
	Path                           string
	apigateway.CreateResourceInput `json:",inline"`
	Methods                        []*ResourceMethod
}

//ResourceMethod represents resource method
type ResourceMethod struct {
	FunctionName string
	HttpMethod   string
	*apigateway.PutMethodInput
	*apigateway.PutIntegrationInput
	*lambda.AddPermissionInput
}

//SetupResourceOutput represents setup resource output
type SetupResourceOutput struct {
	*apigateway.Resource `json:",inline"`
	ResourceMethods      map[string]*apigateway.Method
}

//RemoveRestAPI removes API for supplied name
type RemoveRestAPIInput struct {
	Name *string
}

func (i *RemoveRestAPIInput) Validate() error {
	if i.Name == nil {
		return errors.New("name was empty")
	}
	return nil
}

func (i *SetupRestAPIInput) Init() error {
	if len(i.Resources) == 0 {
		return nil
	}

	var URIs = make(map[string]bool)
	var resources = make([]*SetupResourceInput, 0)

	for _, resource := range i.Resources {
		if err := resource.Init(); err != nil {
			return err
		}
		URIs[resource.Path] = true

		parts := strings.Split(resource.Path, "/")

		for i := 1; i < len(parts)-1; i++ {
			ancestor := strings.Join(parts[0:i+1], "/")
			if URIs[ancestor] {
				continue
			}
			ancestorResource := &SetupResourceInput{Path: ancestor}
			_ = ancestorResource.Init()
			resources = append(resources, ancestorResource)
		}
		resources = append(resources, resource)
	}
	i.Resources = resources
	return nil
}

//Validate checks is input is valud
func (i *SetupRestAPIInput) Validate() error {
	if len(i.Resources) == 0 {
		return fmt.Errorf("resources was empty")
	}
	for _, resource := range i.Resources {
		if err := resource.Validate(); err != nil {
			return err
		}
	}
	createDeployment := &i.CreateDeploymentInput
	if createDeployment.StageName == nil {
		createDeployment.StageName = aws.String("e2e")
	}
	return nil
}

//Init initialize input
func (i *SetupResourceInput) Init() error {
	if i.Path == "" {
		if i.PathPart != nil {
			i.Path = "/" + *i.PathPart
		} else {
			i.Path = "/"
		}
	}
	if i.PathPart == nil {
		parts := strings.Split(i.Path, "/")
		if len(parts) > 1 {
			i.PathPart = &parts[len(parts)-1]
		}
	}
	if len(i.Methods) == 0 {
		return nil
	}
	for _, method := range i.Methods {
		if err := method.Init(); err != nil {
			return err
		}
	}
	return nil
}

func (i *SetupResourceInput) Validate() error {
	resourceInput := i.CreateResourceInput
	if resourceInput.PathPart == nil {
		return fmt.Errorf("pathPart was empty")
	}
	if len(i.Methods) > 0 {
		for _, method := range i.Methods {
			if err := method.Validate(); err != nil {
				return err
			}
		}
	}
	return nil
}

//ParentPath returns parent path
func (i *SetupResourceInput) ParentPath() string {
	if i.PathPart == nil {
		return i.Path
	}
	index := strings.LastIndex(i.Path, *i.PathPart)
	if index == -1 {
		return i.Path
	}
	result := string(i.Path[:index])
	if result == "/" {
		return result
	}
	if strings.HasSuffix(result, "/") {
		return string(result[:len(result)-1])
	}
	return result
}

/*
	Initialise resource with the following defaults

AuthorizationType: NONE

HttpMethod: ANY

ApiKeyRequired: false

IntegrationHttpMethod: POST

Type: AWS_PROXY

Uri: arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/${function.arn}/invocations

	It supports data substitution on uri attribute i.e.
	- 	$function.arn
	-	$function.region
	-	$function.accountID
	-	$restAPI.ID
	-	$uuid.next

*/
func (i *ResourceMethod) Init() error {

	methodInput := i.PutMethodInput
	if methodInput == nil {
		i.PutMethodInput = &apigateway.PutMethodInput{}
		methodInput = i.PutMethodInput
	}
	if methodInput != nil {
		methodInput.AuthorizationType = aws.String("NONE")
	}

	if methodInput.ApiKeyRequired == nil {
		methodInput.ApiKeyRequired = aws.Bool(false)
	}
	integrationInput := i.PutIntegrationInput
	if integrationInput == nil {
		i.PutIntegrationInput = &apigateway.PutIntegrationInput{}
		integrationInput = i.PutIntegrationInput
	}

	if i.HttpMethod != "" {
		methodInput.HttpMethod = &i.HttpMethod
		integrationInput.HttpMethod = &i.HttpMethod
	}

	if integrationInput.HttpMethod == nil {
		integrationInput.HttpMethod = methodInput.HttpMethod
	}
	if integrationInput.IntegrationHttpMethod == nil {
		integrationInput.IntegrationHttpMethod = aws.String("POST")
	}

	if i.FunctionName != "" {
		if integrationInput.Type == nil {
			integrationInput.Type = aws.String("AWS_PROXY")
		}

		if integrationInput.Uri == nil {
			integrationInput.Uri = aws.String("arn:aws:apigateway:${function.region}:lambda:path/2015-03-31/functions/${function.arn}/invocations")
		}
		permissionInput := i.AddPermissionInput
		if i.AddPermissionInput == nil {
			i.AddPermissionInput = &lambda.AddPermissionInput{}
			permissionInput = i.AddPermissionInput
		}
		if permissionInput.FunctionName == nil {
			permissionInput.FunctionName = &i.FunctionName
		}
		if permissionInput.Action == nil {
			permissionInput.Action = aws.String("lambda:InvokeFunction")
		}
		if permissionInput.Principal == nil {
			permissionInput.Principal = aws.String("apigateway.amazonaws.com")
		}
		if permissionInput.StatementId == nil {
			permissionInput.StatementId = aws.String("${uuid.next}")
		}
		if permissionInput.SourceArn == nil {
			permissionInput.SourceArn = aws.String("arn:aws:execute-api:${function.region}:${function.accountID}:${restAPI.ID}/*/*/*")
		}
	}
	return nil
}

func (i *ResourceMethod) Validate() error {
	if i.HttpMethod == "" {
		return fmt.Errorf("httpMethod was empty")
	}
	if i.Type == nil {
		return fmt.Errorf("type was empty")
	}
	return nil
}

//SetupMethodInput setups method input
type SetupMethodInput apigateway.PutMethodInput

//Diff computes patches
func (i SetupMethodInput) Diff(source *apigateway.Method) []*apigateway.PatchOperation {
	var result = make([]*apigateway.PatchOperation, 0)
	if patch, ok := patchBool(source.ApiKeyRequired, i.ApiKeyRequired, "/apiKeyRequired"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.AuthorizationType, i.AuthorizationType, "/authorizationType"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.AuthorizerId, i.AuthorizerId, "/authorizerId"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.OperationName, i.OperationName, "/operationName"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.RequestValidatorId, i.RequestValidatorId, "/requestValidatorId"); ok {
		result = append(result, patch)
	}
	return result
}

type PutIntegrationInput apigateway.PutIntegrationInput

//Diff computes patches
func (i PutIntegrationInput) Diff(source *apigateway.Integration) []*apigateway.PatchOperation {
	var result = make([]*apigateway.PatchOperation, 0)
	if patch, ok := patchString(source.Uri, i.Uri, "/uri"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.Credentials, i.Credentials, "/credentials"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.Type, i.Type, "/integrationType"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.ConnectionId, i.ConnectionId, "/connectionId"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.ConnectionType, i.ConnectionType, "/connectionType"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.ContentHandling, i.ContentHandling, "/contentHandling"); ok {
		result = append(result, patch)
	}
	if i.PassthroughBehavior != nil {
		if patch, ok := patchString(source.PassthroughBehavior, i.PassthroughBehavior, "/passthroughBehavior"); ok {
			result = append(result, patch)
		}
	}
	return result
}

type SetupDeploymentInput apigateway.CreateDeploymentInput

func (i *SetupDeploymentInput) Diff(source *apigateway.CreateDeploymentInput) []*apigateway.PatchOperation {
	var result = make([]*apigateway.PatchOperation, 0)
	if patch, ok := patchString(source.StageName, i.StageName, "/stageName"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.Description, i.Description, "/description"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchString(source.StageDescription, i.StageDescription, "/stageDescription"); ok {
		result = append(result, patch)
	}
	if patch, ok := patchBool(source.CacheClusterEnabled, i.CacheClusterEnabled, "/cacheClusterEnabled"); ok {
		result = append(result, patch)
	}

	return result
}
<|endoftext|>