<commit_before>package aero

import (
	"fmt"
	"io"
	"strings"

	"github.com/akyoto/color"
)

// node types
const (
	separator = '/'
	parameter = ':'
	wildcard  = '*'
)

// controlFlow tells the main loop what it should do next.
type controlFlow int

// controlFlow values.
const (
	controlStop  controlFlow = 0
	controlBegin controlFlow = 1
	controlNext  controlFlow = 2
)

// dataType specifies which type of data we are going to save for each node.
type dataType = Handler

// tree represents a radix tree.
type tree struct {
	prefix    string
	children  [224]*tree
	data      dataType
	parameter *tree
	wildcard  *tree
	kind      byte
}

// add adds a new element to the tree.
func (node *tree) add(path string, data dataType) {
	// Search tree for equal parts until we can no longer proceed
	i := 0
	offset := 0

	for {
	begin:
		switch node.kind {
		case parameter:
			// This only occurs when the same parameter based route is added twice.
			// node: /post/:id|
			// path: /post/:id|
			if i == len(path) {
				node.data = data
				return
			}

			// When we hit a separator, we'll search for a fitting child.
			if path[i] == separator {
				var control controlFlow
				node, offset, control = node.end(path, data, i, offset)

				switch control {
				case controlStop:
					return
				case controlBegin:
					goto begin
				case controlNext:
					goto next
				}
			}

		default:
			if i == len(path) {
				// The path already exists.
				// node: /blog|
				// path: /blog|
				if i-offset == len(node.prefix) {
					node.data = data
					return
				}

				// The path ended but the node prefix is longer.
				// node: /blog|feed
				// path: /blog|
				node.split(i-offset, "", data)
				return
			}

			// The node we just checked is entirely included in our path.
			// node: /|
			// path: /|blog
			if i-offset == len(node.prefix) {
				var control controlFlow
				node, offset, control = node.end(path, data, i, offset)

				switch control {
				case controlStop:
					return
				case controlBegin:
					goto begin
				case controlNext:
					goto next
				}
			}

			// We got a conflict.
			// node: /b|ag
			// path: /b|riefcase
			if path[i] != node.prefix[i-offset] {
				node.split(i-offset, path[i:], data)
				return
			}
		}

	next:
		i++
	}
}

// split splits the node at the given index and inserts
// a new child node with the given path and data.
// If path is empty, it will not create another child node
// and instead assign the data directly to the node.
func (node *tree) split(index int, path string, data dataType) {
	// Create split node with the remaining string
	splitNode := node.clone(node.prefix[index:])

	/// The existing data must be removed
	node.reset(node.prefix[:index])

	// If the path is empty, it means we don't create a 2nd child node.
	// Just assign the data for the existing node and store a single child node.
	if path == "" {
		node.data = data
		node.children[splitNode.prefix[0]-32] = splitNode
		return
	}

	node.children[splitNode.prefix[0]-32] = splitNode

	// Create new nodes with the remaining path
	node.append(path, data)
}

// clone clones the node with a new prefix.
func (node *tree) clone(prefix string) *tree {
	return &tree{
		prefix:    prefix,
		data:      node.data,
		children:  node.children,
		parameter: node.parameter,
		wildcard:  node.wildcard,
		kind:      node.kind,
	}
}

// reset resets the existing node data.
func (node *tree) reset(prefix string) {
	node.prefix = prefix
	node.data = nil
	node.parameter = nil
	node.wildcard = nil
	node.kind = 0
	node.children = [224]*tree{}
}

// addTrailingSlash adds a trailing slash with the same data.
func (node *tree) addTrailingSlash(data dataType) {
	if strings.HasSuffix(node.prefix, "/") || node.children[separator-32] != nil || node.kind == wildcard {
		return
	}

	node.children[separator-32] = &tree{
		prefix: "/",
		data:   data,
	}
}

// append appends the given path to the tree.
func (node *tree) append(path string, data dataType) {
	// At this point, all we know is that somewhere
	// in the remaining string we have parameters.
	// node: /user|
	// path: /user|/:userid
	for {
		if path == "" {
			node.data = data
			return
		}

		paramStart := strings.IndexByte(path, parameter)

		if paramStart == -1 {
			paramStart = strings.IndexByte(path, wildcard)
		}

		// If it's a static route we are adding,
		// just add the remainder as a normal node.
		if paramStart == -1 {
			// If the node itself doesn't have a prefix (root node),
			// don't add a child and use the node itself.
			if node.prefix == "" {
				node.prefix = path
				node.data = data
				return
			}

			child := &tree{
				prefix: path,
				data:   data,
			}

			node.children[path[0]-32] = child
			child.addTrailingSlash(data)
			return
		}

		// If we're directly in front of a parameter,
		// add a parameter node.
		if paramStart == 0 {
			paramEnd := strings.IndexByte(path, separator)

			if paramEnd == -1 {
				paramEnd = len(path)
			}

			child := &tree{
				prefix: path[1:paramEnd],
				kind:   path[paramStart],
			}

			switch child.kind {
			case parameter:
				child.addTrailingSlash(data)
				node.parameter = child
				node = child
				path = path[paramEnd:]
				continue

			case wildcard:
				child.data = data
				node.wildcard = child
				return
			}
		}

		// We know there's a parameter, but not directly at the start.

		// If the node itself doesn't have a prefix (root node),
		// don't add a child and use the node itself.
		if node.prefix == "" {
			node.prefix = path[:paramStart]
			path = path[paramStart:]
			continue
		}

		// Add a normal node with the path before the parameter start.
		child := &tree{
			prefix: path[:paramStart],
		}

		// Allow trailing slashes to return
		// the same content as their parent node.
		if child.prefix == "/" {
			child.data = node.data
		}

		node.children[path[0]-32] = child
		node = child
		path = path[paramStart:]
	}
}

// end is called when the node was fully parsed
// and needs to decide the next control flow.
func (node *tree) end(path string, data dataType, i int, offset int) (*tree, int, controlFlow) {
	child := node.children[path[i]-32]

	if child != nil {
		node = child
		offset = i
		return node, offset, controlNext
	}

	// No fitting children found, does this node even contain a prefix yet?
	// If no prefix is set, this is the starting node.
	if node.prefix == "" {
		node.append(path[i:], data)
		return node, offset, controlStop
	}

	// node: /user/|:id
	// path: /user/|:id/profile
	if node.parameter != nil {
		node = node.parameter
		offset = i
		return node, offset, controlBegin
	}

	node.append(path[i:], data)
	return node, offset, controlStop
}

// find finds the data for the given path and assigns it to ctx.handler, if available.
func (node *tree) find(path string, ctx *context) {
	var (
		i                  uint
		offset             uint
		lastWildcardOffset uint
		lastWildcard       *tree
	)

	// Search tree for equal parts until we can no longer proceed
	for {
		if node.kind == parameter {
			if i == uint(len(path)) {
				ctx.addParameter(node.prefix, path[offset:i])
				ctx.handler = node.data
				return
			}

			if path[i] == separator {
				ctx.addParameter(node.prefix, path[offset:i])
				node = node.children[separator-32]
				offset = i
				i++
				continue
			}

			i++
			continue
		}

		// We reached the end.
		if i == uint(len(path)) {
			// node: /blog|
			// path: /blog|
			if i-offset == uint(len(node.prefix)) {
				ctx.handler = node.data
				return
			}

			// node: /blog|feed
			// path: /blog|
			ctx.handler = nil
			return
		}

		// The node we just checked is entirely included in our path.
		// node: /|
		// path: /|blog
		if i-offset == uint(len(node.prefix)) {
			if node.wildcard != nil {
				lastWildcard = node.wildcard
				lastWildcardOffset = i
			}

			child := node.children[path[i]-32]

			if child != nil {
				node = child
				offset = i
				i++
				continue
			}

			// node: /|:id
			// path: /|blog
			if node.parameter != nil {
				node = node.parameter
				offset = i
				continue
			}

			// node: /|*any
			// path: /|image.png
			if node.wildcard != nil {
				ctx.addParameter(node.wildcard.prefix, path[i:])
				ctx.handler = node.wildcard.data
				return
			}

			ctx.handler = nil
			return
		}

		// We got a conflict.
		// node: /b|ag
		// path: /b|riefcase
		if path[i] != node.prefix[i-offset] {
			if lastWildcard != nil {
				ctx.addParameter(lastWildcard.prefix, path[lastWildcardOffset:])
				ctx.handler = lastWildcard.data
				return
			}

			ctx.handler = nil
			return
		}

		i++
	}
}

// each traverses the tree and calls the given function on every node.
func (node *tree) each(callback func(*tree)) {
	callback(node)

	for _, child := range node.children {
		if child == nil {
			continue
		}

		child.each(callback)
	}

	if node.parameter != nil {
		node.parameter.each(callback)
	}

	if node.wildcard != nil {
		node.wildcard.each(callback)
	}
}

// PrettyPrint prints a human-readable form of the tree to the given writer.
func (node *tree) PrettyPrint(writer io.Writer) {
	node.prettyPrint(writer, -1)
}

// prettyPrint
func (node *tree) prettyPrint(writer io.Writer, level int) {
	prefix := ""

	if level >= 0 {
		prefix = strings.Repeat("  ", level) + "|_ "
	}

	colorFunc := color.CyanString

	switch node.kind {
	case ':':
		prefix += ":"
		colorFunc = color.YellowString
	case '*':
		prefix += "*"
		colorFunc = color.GreenString
	}

	fmt.Fprintf(writer, "%s%s [%t]\n", prefix, colorFunc(node.prefix), node.data != nil)

	for _, child := range node.children {
		if child == nil {
			continue
		}

		child.prettyPrint(writer, level+1)
	}

	if node.parameter != nil {
		node.parameter.prettyPrint(writer, level+1)
	}

	if node.wildcard != nil {
		node.wildcard.prettyPrint(writer, level+1)
	}
}
<commit_msg>Added a few comments<commit_after>package aero

import (
	"fmt"
	"io"
	"strings"

	"github.com/akyoto/color"
)

// node types
const (
	separator = '/'
	parameter = ':'
	wildcard  = '*'
)

// controlFlow tells the main loop what it should do next.
type controlFlow int

// controlFlow values.
const (
	controlStop  controlFlow = 0
	controlBegin controlFlow = 1
	controlNext  controlFlow = 2
)

// dataType specifies which type of data we are going to save for each node.
type dataType = Handler

// tree represents a radix tree.
type tree struct {
	prefix    string
	children  [224]*tree
	data      dataType
	parameter *tree
	wildcard  *tree
	kind      byte
}

// add adds a new element to the tree.
func (node *tree) add(path string, data dataType) {
	// Search tree for equal parts until we can no longer proceed
	i := 0
	offset := 0

	for {
	begin:
		switch node.kind {
		case parameter:
			// This only occurs when the same parameter based route is added twice.
			// node: /post/:id|
			// path: /post/:id|
			if i == len(path) {
				node.data = data
				return
			}

			// When we hit a separator, we'll search for a fitting child.
			if path[i] == separator {
				var control controlFlow
				node, offset, control = node.end(path, data, i, offset)

				switch control {
				case controlStop:
					return
				case controlBegin:
					goto begin
				case controlNext:
					goto next
				}
			}

		default:
			if i == len(path) {
				// The path already exists.
				// node: /blog|
				// path: /blog|
				if i-offset == len(node.prefix) {
					node.data = data
					return
				}

				// The path ended but the node prefix is longer.
				// node: /blog|feed
				// path: /blog|
				node.split(i-offset, "", data)
				return
			}

			// The node we just checked is entirely included in our path.
			// node: /|
			// path: /|blog
			if i-offset == len(node.prefix) {
				var control controlFlow
				node, offset, control = node.end(path, data, i, offset)

				switch control {
				case controlStop:
					return
				case controlBegin:
					goto begin
				case controlNext:
					goto next
				}
			}

			// We got a conflict.
			// node: /b|ag
			// path: /b|riefcase
			if path[i] != node.prefix[i-offset] {
				node.split(i-offset, path[i:], data)
				return
			}
		}

	next:
		i++
	}
}

// split splits the node at the given index and inserts
// a new child node with the given path and data.
// If path is empty, it will not create another child node
// and instead assign the data directly to the node.
func (node *tree) split(index int, path string, data dataType) {
	// Create split node with the remaining string
	splitNode := node.clone(node.prefix[index:])

	/// The existing data must be removed
	node.reset(node.prefix[:index])

	// If the path is empty, it means we don't create a 2nd child node.
	// Just assign the data for the existing node and store a single child node.
	if path == "" {
		node.data = data
		node.children[splitNode.prefix[0]-32] = splitNode
		return
	}

	node.children[splitNode.prefix[0]-32] = splitNode

	// Create new nodes with the remaining path
	node.append(path, data)
}

// clone clones the node with a new prefix.
func (node *tree) clone(prefix string) *tree {
	return &tree{
		prefix:    prefix,
		data:      node.data,
		children:  node.children,
		parameter: node.parameter,
		wildcard:  node.wildcard,
		kind:      node.kind,
	}
}

// reset resets the existing node data.
func (node *tree) reset(prefix string) {
	node.prefix = prefix
	node.data = nil
	node.parameter = nil
	node.wildcard = nil
	node.kind = 0
	node.children = [224]*tree{}
}

// addTrailingSlash adds a trailing slash with the same data.
func (node *tree) addTrailingSlash(data dataType) {
	if strings.HasSuffix(node.prefix, "/") || node.children[separator-32] != nil || node.kind == wildcard {
		return
	}

	node.children[separator-32] = &tree{
		prefix: "/",
		data:   data,
	}
}

// append appends the given path to the tree.
func (node *tree) append(path string, data dataType) {
	// At this point, all we know is that somewhere
	// in the remaining string we have parameters.
	// node: /user|
	// path: /user|/:userid
	for {
		if path == "" {
			node.data = data
			return
		}

		paramStart := strings.IndexByte(path, parameter)

		if paramStart == -1 {
			paramStart = strings.IndexByte(path, wildcard)
		}

		// If it's a static route we are adding,
		// just add the remainder as a normal node.
		if paramStart == -1 {
			// If the node itself doesn't have a prefix (root node),
			// don't add a child and use the node itself.
			if node.prefix == "" {
				node.prefix = path
				node.data = data
				return
			}

			child := &tree{
				prefix: path,
				data:   data,
			}

			node.children[path[0]-32] = child
			child.addTrailingSlash(data)
			return
		}

		// If we're directly in front of a parameter,
		// add a parameter node.
		if paramStart == 0 {
			paramEnd := strings.IndexByte(path, separator)

			if paramEnd == -1 {
				paramEnd = len(path)
			}

			child := &tree{
				prefix: path[1:paramEnd],
				kind:   path[paramStart],
			}

			switch child.kind {
			case parameter:
				child.addTrailingSlash(data)
				node.parameter = child
				node = child
				path = path[paramEnd:]
				continue

			case wildcard:
				child.data = data
				node.wildcard = child
				return
			}
		}

		// We know there's a parameter, but not directly at the start.

		// If the node itself doesn't have a prefix (root node),
		// don't add a child and use the node itself.
		if node.prefix == "" {
			node.prefix = path[:paramStart]
			path = path[paramStart:]
			continue
		}

		// Add a normal node with the path before the parameter start.
		child := &tree{
			prefix: path[:paramStart],
		}

		// Allow trailing slashes to return
		// the same content as their parent node.
		if child.prefix == "/" {
			child.data = node.data
		}

		node.children[path[0]-32] = child
		node = child
		path = path[paramStart:]
	}
}

// end is called when the node was fully parsed
// and needs to decide the next control flow.
func (node *tree) end(path string, data dataType, i int, offset int) (*tree, int, controlFlow) {
	child := node.children[path[i]-32]

	if child != nil {
		node = child
		offset = i
		return node, offset, controlNext
	}

	// No fitting children found, does this node even contain a prefix yet?
	// If no prefix is set, this is the starting node.
	if node.prefix == "" {
		node.append(path[i:], data)
		return node, offset, controlStop
	}

	// node: /user/|:id
	// path: /user/|:id/profile
	if node.parameter != nil {
		node = node.parameter
		offset = i
		return node, offset, controlBegin
	}

	node.append(path[i:], data)
	return node, offset, controlStop
}

// find finds the data for the given path and assigns it to ctx.handler, if available.
func (node *tree) find(path string, ctx *context) {
	var (
		i                  uint
		offset             uint
		lastWildcardOffset uint
		lastWildcard       *tree
	)

	// Search tree for equal parts until we can no longer proceed
	for {
		if node.kind == parameter {
			// We reached the end.
			if i == uint(len(path)) {
				ctx.addParameter(node.prefix, path[offset:i])
				ctx.handler = node.data
				return
			}

			// node: /:xxx|/:yyy
			// path: /blog|/post
			if path[i] == separator {
				ctx.addParameter(node.prefix, path[offset:i])
				node = node.children[separator-32]
				offset = i
				i++
				continue
			}

			i++
			continue
		}

		// We reached the end.
		if i == uint(len(path)) {
			// node: /blog|
			// path: /blog|
			if i-offset == uint(len(node.prefix)) {
				ctx.handler = node.data
				return
			}

			// node: /blog|feed
			// path: /blog|
			ctx.handler = nil
			return
		}

		// The node we just checked is entirely included in our path.
		// node: /|
		// path: /|blog
		if i-offset == uint(len(node.prefix)) {
			if node.wildcard != nil {
				lastWildcard = node.wildcard
				lastWildcardOffset = i
			}

			child := node.children[path[i]-32]

			if child != nil {
				node = child
				offset = i
				i++
				continue
			}

			// node: /|:id
			// path: /|blog
			if node.parameter != nil {
				node = node.parameter
				offset = i
				continue
			}

			// node: /|*any
			// path: /|image.png
			if node.wildcard != nil {
				ctx.addParameter(node.wildcard.prefix, path[i:])
				ctx.handler = node.wildcard.data
				return
			}

			ctx.handler = nil
			return
		}

		// We got a conflict.
		// node: /b|ag
		// path: /b|riefcase
		if path[i] != node.prefix[i-offset] {
			if lastWildcard != nil {
				ctx.addParameter(lastWildcard.prefix, path[lastWildcardOffset:])
				ctx.handler = lastWildcard.data
				return
			}

			ctx.handler = nil
			return
		}

		i++
	}
}

// each traverses the tree and calls the given function on every node.
func (node *tree) each(callback func(*tree)) {
	callback(node)

	for _, child := range node.children {
		if child == nil {
			continue
		}

		child.each(callback)
	}

	if node.parameter != nil {
		node.parameter.each(callback)
	}

	if node.wildcard != nil {
		node.wildcard.each(callback)
	}
}

// PrettyPrint prints a human-readable form of the tree to the given writer.
func (node *tree) PrettyPrint(writer io.Writer) {
	node.prettyPrint(writer, -1)
}

// prettyPrint
func (node *tree) prettyPrint(writer io.Writer, level int) {
	prefix := ""

	if level >= 0 {
		prefix = strings.Repeat("  ", level) + "|_ "
	}

	colorFunc := color.CyanString

	switch node.kind {
	case ':':
		prefix += ":"
		colorFunc = color.YellowString
	case '*':
		prefix += "*"
		colorFunc = color.GreenString
	}

	fmt.Fprintf(writer, "%s%s [%t]\n", prefix, colorFunc(node.prefix), node.data != nil)

	for _, child := range node.children {
		if child == nil {
			continue
		}

		child.prettyPrint(writer, level+1)
	}

	if node.parameter != nil {
		node.parameter.prettyPrint(writer, level+1)
	}

	if node.wildcard != nil {
		node.wildcard.prettyPrint(writer, level+1)
	}
}
<|endoftext|>


<commit_before>package trek

import (
	"database/sql"
	"errors"
	"reflect"
	"sort"
)

var (
	migrations                   []migration
	errNoRows                    = errors.New("sql: no rows in result set")
	errUnrecognizedDatabase      = errors.New("trek: unrecognized database")
	errUnrecognizedAction        = errors.New("trek: unrecognized action")
	errPreviousMigrationNotFound = errors.New("trek: previous migration not found")
)

const (
	// UP migrates the database to the latest version
	UP = "up"
	// DOWN migrates the database to a previous version
	DOWN = "down"
	// POSTGRES is a supported database
	POSTGRES = "postgres"
	// MYSQL is a supported database
	MYSQL = "mysql"
)

// Register adds migrations to be runned
func Register(version int64, up, down migrationHandler) {
	migrations = append(migrations, migration{
		Version: version,
		Up:      up,
		Down:    down,
	})
}

// Run executes database migrations
func Run(db *sql.DB, options ...interface{}) (didChange bool, newVersion int64, err error) {
	if len(migrations) == 0 {
		return
	}

	sort.Sort(byVersion(migrations))

	config := parseOptions(options)
	dtbs := &database{db, config}

	err = createTable(dtbs)
	if err != nil {
		return
	}

	oldVersion, err := getVersion(dtbs)
	if err != nil {
		return
	}

	newVersion, err = runMigrations(dtbs, oldVersion)
	didChange = oldVersion != newVersion
	return
}

func parseOptions(options []interface{}) *configuration {
	config := configuration{Action: UP, Database: POSTGRES}

	for _, opt := range options {
		value := reflect.ValueOf(opt)
		if value.Kind() == reflect.String {
			str := value.String()
			switch str {
			case UP:
			case DOWN:
				config.Action = str
				break
			case POSTGRES:
			case MYSQL:
				config.Database = str
				break
			}
		}
	}

	return &config
}

func createTable(db *database) error {
	var query string

	switch db.Database {
	case POSTGRES:
		query = `CREATE TABLE IF NOT EXISTS migrations (id SERIAL PRIMARY KEY, version BIGINT NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW())`
		break
	case MYSQL:
		query = `CREATE TABLE IF NOT EXISTS migrations (id BIGINT PRIMARY KEY AUTO_INCREMENT, version BIGINT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)`
		break
	default:
		return errUnrecognizedDatabase
	}

	_, err := db.Exec(query)
	return err
}

func getVersion(db *database) (currentVersion int64, err error) {
	err = db.QueryRow(`SELECT version FROM migrations ORDER BY id DESC LIMIT 1`).Scan(&currentVersion)
	if err != nil && err.Error() == errNoRows.Error() {
		currentVersion = 0
		err = nil
	}
	return
}

func runMigrations(db *database, oldVersion int64) (newVersion int64, err error) {
	switch db.Action {
	case UP:
		newVersion, err = runUp(db, oldVersion)
		break
	case DOWN:
		newVersion, err = runDown(db, oldVersion)
		break
	default:
		err = errUnrecognizedAction
	}

	return
}

func runUp(db *database, oldVersion int64) (newVersion int64, err error) {
	for _, m := range migrations {
		if m.Version <= oldVersion {
			continue
		}

		if m.Up != nil {
			err = m.Up(db.DB)
			if err != nil {
				return
			}
		}

		err = setVersion(db, m.Version)
		if err != nil {
			return
		}

		newVersion = m.Version
	}

	return
}

func runDown(db *database, oldVersion int64) (newVersion int64, err error) {
	if oldVersion == 0 {
		return
	}

	var m *migration
	for i := len(migrations) - 1; i >= 0; i-- {
		if migrations[i].Version <= oldVersion {
			m = &migrations[i]
			break
		}
	}

	if m == nil {
		err = errPreviousMigrationNotFound
		return
	}

	if m.Down != nil {
		err = m.Down(db.DB)
		if err != nil {
			return
		}
	}

	newVersion = m.Version - 1
	err = setVersion(db, newVersion)
	return
}

func setVersion(db *database, version int64) error {
	var query string

	switch db.Database {
	case POSTGRES:
		query = `INSERT INTO migrations (version) VALUES ($1)`
		break
	case MYSQL:
		query = `INSERT INTO migrations (version) VALUES (?)`
		break
	default:
		return errUnrecognizedDatabase
	}

	stmt, err := db.Prepare(query)
	if err != nil {
		return err
	}

	_, err = stmt.Exec(version)
	return err
}

type migrationHandler func(*sql.DB) error

type configuration struct {
	Action   string
	Database string
}

type database struct {
	*sql.DB
	*configuration
}

type migration struct {
	Version int64
	Up      migrationHandler
	Down    migrationHandler
}

type byVersion []migration

func (s byVersion) Len() int { return len(s) }

func (s byVersion) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func (s byVersion) Less(i, j int) bool { return s[i].Version < s[j].Version }
<commit_msg>Allow only one migration by version number<commit_after>package trek

import (
	"database/sql"
	"errors"
	"reflect"
	"sort"
)

var (
	migrations                   []migration
	errNoRows                    = errors.New("sql: no rows in result set")
	errUnrecognizedDatabase      = errors.New("trek: unrecognized database")
	errUnrecognizedAction        = errors.New("trek: unrecognized action")
	errPreviousMigrationNotFound = errors.New("trek: previous migration not found")
	errVersionAlreadyRegistered  = errors.New("Version already registered")
)

const (
	// UP migrates the database to the latest version
	UP = "up"
	// DOWN migrates the database to a previous version
	DOWN = "down"
	// POSTGRES is a supported database
	POSTGRES = "postgres"
	// MYSQL is a supported database
	MYSQL = "mysql"
)

// Register adds migrations to be runned
func Register(version int64, up, down migrationHandler) error {
	if versionAlreadyRegistered(version) {
		return errVersionAlreadyRegistered
	}
	migrations = append(migrations, migration{
		Version: version,
		Up:      up,
		Down:    down,
	})
	return nil
}

// Run executes database migrations
func Run(db *sql.DB, options ...interface{}) (didChange bool, newVersion int64, err error) {
	if len(migrations) == 0 {
		return
	}

	sort.Sort(byVersion(migrations))

	config := parseOptions(options)
	dtbs := &database{db, config}

	err = createTable(dtbs)
	if err != nil {
		return
	}

	oldVersion, err := getVersion(dtbs)
	if err != nil {
		return
	}

	newVersion, err = runMigrations(dtbs, oldVersion)
	didChange = oldVersion != newVersion
	return
}

func parseOptions(options []interface{}) *configuration {
	config := configuration{Action: UP, Database: POSTGRES}

	for _, opt := range options {
		value := reflect.ValueOf(opt)
		if value.Kind() == reflect.String {
			str := value.String()
			switch str {
			case UP:
			case DOWN:
				config.Action = str
				break
			case POSTGRES:
			case MYSQL:
				config.Database = str
				break
			}
		}
	}

	return &config
}

func createTable(db *database) error {
	var query string

	switch db.Database {
	case POSTGRES:
		query = `CREATE TABLE IF NOT EXISTS migrations (id SERIAL PRIMARY KEY, version BIGINT NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW())`
		break
	case MYSQL:
		query = `CREATE TABLE IF NOT EXISTS migrations (id BIGINT PRIMARY KEY AUTO_INCREMENT, version BIGINT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)`
		break
	default:
		return errUnrecognizedDatabase
	}

	_, err := db.Exec(query)
	return err
}

func getVersion(db *database) (currentVersion int64, err error) {
	err = db.QueryRow(`SELECT version FROM migrations ORDER BY id DESC LIMIT 1`).Scan(&currentVersion)
	if err != nil && err.Error() == errNoRows.Error() {
		currentVersion = 0
		err = nil
	}
	return
}

func runMigrations(db *database, oldVersion int64) (newVersion int64, err error) {
	switch db.Action {
	case UP:
		newVersion, err = runUp(db, oldVersion)
		break
	case DOWN:
		newVersion, err = runDown(db, oldVersion)
		break
	default:
		err = errUnrecognizedAction
	}

	return
}

func runUp(db *database, oldVersion int64) (newVersion int64, err error) {
	for _, m := range migrations {
		if m.Version <= oldVersion {
			continue
		}

		if m.Up != nil {
			err = m.Up(db.DB)
			if err != nil {
				return
			}
		}

		err = setVersion(db, m.Version)
		if err != nil {
			return
		}

		newVersion = m.Version
	}

	return
}

func runDown(db *database, oldVersion int64) (newVersion int64, err error) {
	if oldVersion == 0 {
		return
	}

	var m *migration
	for i := len(migrations) - 1; i >= 0; i-- {
		if migrations[i].Version <= oldVersion {
			m = &migrations[i]
			break
		}
	}

	if m == nil {
		err = errPreviousMigrationNotFound
		return
	}

	if m.Down != nil {
		err = m.Down(db.DB)
		if err != nil {
			return
		}
	}

	newVersion = m.Version - 1
	err = setVersion(db, newVersion)
	return
}

func setVersion(db *database, version int64) error {
	var query string

	switch db.Database {
	case POSTGRES:
		query = `INSERT INTO migrations (version) VALUES ($1)`
		break
	case MYSQL:
		query = `INSERT INTO migrations (version) VALUES (?)`
		break
	default:
		return errUnrecognizedDatabase
	}

	stmt, err := db.Prepare(query)
	if err != nil {
		return err
	}

	_, err = stmt.Exec(version)
	return err
}

func versionAlreadyRegistered(version int64) bool {
	for _, m := range migrations {
		if m.Version == version {
			return true
		}
	}
	return false
}

type migrationHandler func(*sql.DB) error

type configuration struct {
	Action   string
	Database string
}

type database struct {
	*sql.DB
	*configuration
}

type migration struct {
	Version int64
	Up      migrationHandler
	Down    migrationHandler
}

type byVersion []migration

func (s byVersion) Len() int { return len(s) }

func (s byVersion) Swap(i, j int) { s[i], s[j] = s[j], s[i] }

func (s byVersion) Less(i, j int) bool { return s[i].Version < s[j].Version }
<|endoftext|>


<commit_before>package raft

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

type requestForVote struct {
	Term         int
	CandidateID  string
	LastLogIndex int
	LastLogTerm  int
}

type voteRequest struct {
	Req        requestForVote
	ReturnChan chan requestForVoteResponse
}

type requestForVoteResponse struct {
	Term           int
	HasGrantedVote bool
}

type voteResponse struct {
	ServerIndex int
	Resp        requestForVoteResponse
}

func (s *server) handleRequestForVote(v voteRequest) {
	req := v.Req
	returnChan := v.ReturnChan
	if req.Term < s.term {
		resp := &requestForVoteResponse{s.term, false}
		returnChan <- *resp
	} else {
		cond1 := s.votedFor == ""
		cond2 := s.votedFor == req.CandidateID
		cond3 := req.LastLogIndex >= len(s.db.Log.Entries)-1
		if (cond1 || cond2) && cond3 {
			s.electionTimeout.reset()
			s.votedFor = req.CandidateID
			s.term = req.Term
			resp := &requestForVoteResponse{s.term, true}
			returnChan <- *resp
		}
	}
}

func (s *server) sendRequestForVote(receiverIndex int, respChan chan voteResponse) {
	receiver := s.config[receiverIndex]
	lastLogIndex := len(s.db.Log.Entries) - 1
	lastLogTerm := 0
	if lastLogIndex > 0 {
		lastLogTerm = s.db.Log.Entries[lastLogIndex].Term
	}
	v := &requestForVote{s.term, s.id, lastLogIndex, lastLogTerm}
	b := new(bytes.Buffer)
	json.NewEncoder(b).Encode(v)
	resp, err := http.Post("http://"+receiver+"/votes", "application/json", b)
	if err != nil {
		fmt.Println("Couldn't send request for votes to " + receiver)
		fmt.Println(err)
		return
	} else {
		r := &requestForVoteResponse{}
		err := json.NewDecoder(resp.Body).Decode(r)
		if err != nil {
			fmt.Println("Couldn't decode request for vote response from ", s.config[receiverIndex])
			return
		}
		defer resp.Body.Close()
		voteResp := &voteResponse{receiverIndex, *r}
		respChan <- *voteResp
	}
}

func (s *server) startElection() {
	s.state = "candidate"
	s.term += 1
	voteCount := 1
	respChan := make(chan voteResponse)
	for receiverIndex, receiverId := range s.config {
		if receiverId != s.id {
			go s.sendRequestForVote(receiverIndex, respChan)
		}
	}
	responseCount := 0
	if len(s.config) > 1 {
		for {
			vote := <-respChan
			responseCount++
			if vote.Resp.HasGrantedVote {
				voteCount++
			}
			if voteCount > len(s.config)/2 {
				s.state = "leader"
				break
			}
			if responseCount == len(s.config) {
				break
			}
		}
	}
}
<commit_msg>convert to follower when voting for someone :)<commit_after>package raft

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

type requestForVote struct {
	Term         int
	CandidateID  string
	LastLogIndex int
	LastLogTerm  int
}

type voteRequest struct {
	Req        requestForVote
	ReturnChan chan requestForVoteResponse
}

type requestForVoteResponse struct {
	Term           int
	HasGrantedVote bool
}

type voteResponse struct {
	ServerIndex int
	Resp        requestForVoteResponse
}

func (s *server) handleRequestForVote(v voteRequest) {
	req := v.Req
	returnChan := v.ReturnChan
	if req.Term < s.term {
		resp := &requestForVoteResponse{s.term, false}
		returnChan <- *resp
	} else {
		cond1 := s.votedFor == ""
		cond2 := s.votedFor == req.CandidateID
		cond3 := req.LastLogIndex >= len(s.db.Log.Entries)-1
		if (cond1 || cond2) && cond3 {
			s.state = "follower"
			s.electionTimeout.reset()
			s.votedFor = req.CandidateID
			s.term = req.Term
			resp := &requestForVoteResponse{s.term, true}
			returnChan <- *resp
		}
	}
}

func (s *server) sendRequestForVote(receiverIndex int, respChan chan voteResponse) {
	receiver := s.config[receiverIndex]
	lastLogIndex := len(s.db.Log.Entries) - 1
	lastLogTerm := 0
	if lastLogIndex > 0 {
		lastLogTerm = s.db.Log.Entries[lastLogIndex].Term
	}
	v := &requestForVote{s.term, s.id, lastLogIndex, lastLogTerm}
	b := new(bytes.Buffer)
	json.NewEncoder(b).Encode(v)
	resp, err := http.Post("http://"+receiver+"/votes", "application/json", b)
	if err != nil {
		fmt.Println("Couldn't send request for votes to " + receiver)
		fmt.Println(err)
		return
	} else {
		r := &requestForVoteResponse{}
		err := json.NewDecoder(resp.Body).Decode(r)
		if err != nil {
			fmt.Println("Couldn't decode request for vote response from ", s.config[receiverIndex])
			return
		}
		defer resp.Body.Close()
		voteResp := &voteResponse{receiverIndex, *r}
		respChan <- *voteResp
	}
}

func (s *server) startElection() {
	s.state = "candidate"
	s.term += 1
	voteCount := 1
	respChan := make(chan voteResponse)
	for receiverIndex, receiverId := range s.config {
		if receiverId != s.id {
			go s.sendRequestForVote(receiverIndex, respChan)
		}
	}
	responseCount := 0
	if len(s.config) > 1 {
		for {
			vote := <-respChan
			responseCount++
			if vote.Resp.HasGrantedVote {
				voteCount++
			}
			if voteCount > len(s.config)/2 {
				s.state = "leader"
				break
			}
			if responseCount == len(s.config) {
				break
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"
)

// A Type describes the C and Go type of a function parameter or return value.
type Type struct {
	Name         string // Name of the type without modifiers
	PointerLevel int    // Number of levels of declared indirection to the type
	CDefinition  string // Raw C definition
}

// A Typedef describes a C typedef statement.
type Typedef struct {
	Name        string // Name of the defined type (or included types)
	CDefinition string // Raw C definition
}

func (t Type) String() string {
	return fmt.Sprintf("%s%s [%s]", t.Name, t.pointers(), t.CDefinition)
}

// IsVoid indicates whether this type is the void pseudo-type.
func (t Type) IsVoid() bool {
	return (t.Name == "void" || t.Name == "GLvoid") && t.PointerLevel == 0
}

// IsDebugProc indicates whether this type is a debug callback function pointer.
func (t Type) IsDebugProc() bool {
	return t.Name == "GLDEBUGPROC" || t.Name == "GLDEBUGPROCARB" || t.Name == "GLDEBUGPROCKHR"
}

// CType returns the C definition of the type.
func (t Type) CType() string {
	return t.CDefinition
}

// GoCType returns the Go definition of the C type.
func (t Type) GoCType() string {
	if strings.HasPrefix(t.Name, "struct ") {
		return t.pointers() + "C.struct_" + strings.TrimPrefix(t.Name, "struct ")
	}
	return t.pointers() + "C." + t.Name
}

// GoType returns the Go definition of the type.
func (t Type) GoType() string {
	switch t.Name {
	case "GLbyte":
		return t.pointers() + "int8"
	case "GLubyte":
		return t.pointers() + "uint8"
	case "GLshort":
		return t.pointers() + "int16"
	case "GLushort":
		return t.pointers() + "uint16"
	case "GLint":
		return t.pointers() + "int32"
	case "GLuint":
		return t.pointers() + "uint32"
	case "GLint64", "GLint64EXT":
		return t.pointers() + "int64"
	case "GLuint64", "GLuint64EXT":
		return t.pointers() + "uint64"
	case "GLfloat", "GLclampf":
		return t.pointers() + "float32"
	case "GLdouble", "GLclampd":
		return t.pointers() + "float64"
	case "GLclampx":
		return t.pointers() + "int32"
	case "GLsizei":
		return t.pointers() + "int32"
	case "GLfixed":
		return t.pointers() + "int32"
	case "GLchar", "GLcharARB":
		// Chosen (vs. byte) for compatibility where GL uses GLubyte for strings (e.g., glGetString)
		return t.pointers() + "uint8"
	case "GLboolean":
		return t.pointers() + "bool"
	case "GLenum", "GLbitfield":
		return t.pointers() + "uint32"
	case "GLhalf", "GLhalfNV":
		// Go has no 16-bit floating point type
		return t.pointers() + "uint16"
	case "void", "GLvoid":
		// Type void* could map to either uintptr or unsafe.Pointer but we use the
		// latter because pointers passed from Go to C need to use Go pointer types
		// for the sake of the GC
		if t.PointerLevel == 1 {
			return "unsafe.Pointer"
		} else if t.PointerLevel == 2 {
			return "*unsafe.Pointer"
		}
	case "GLintptr", "GLintptrARB":
		// Type ptrdiff_t should map to an architecture-width Go int
		return t.pointers() + "int"
	case "GLsizeiptr", "GLsizeiptrARB":
		// Same as GLintptr
		return t.pointers() + "int"
	case "GLhandleARB", "GLeglImagesOES", "GLvdpauSurfaceNV":
		// OpenGL pointer types should fit in a pointer-width Go type. No need to
		// use unsafe.Pointer because there is no need for the Go GC to understand
		// that these are pointer types. Moreover on most platforms GLhandleARB is
		// an integer type.
		return t.pointers() + "uintptr"
	case "GLsync":
		// GLsync is an opaque pointer type and may not contain actual
		// pointers but arbitrary numbers. Use uintptr instead of
		// unsafe.Pointer, as the latter requires valid pointers.
		return t.pointers() + "uintptr"
	case "GLDEBUGPROC", "GLDEBUGPROCARB", "GLDEBUGPROCKHR":
		// Special case mapping to the type defined in debug.tmpl
		return "DebugProc"
	}
	return t.GoCType()
}

// ConvertGoToC returns an expression that converts a variable from the Go type to the C type.
func (t Type) ConvertGoToC(name string) string {
	switch t.Name {
	case "GLboolean":
		if t.PointerLevel == 0 {
			return fmt.Sprintf("(C.GLboolean)(boolToInt(%s))", name)
		}
	case "void", "GLvoid":
		return name
	case "GLDEBUGPROC", "GLDEBUGPROCARB", "GLDEBUGPROCKHR":
		return fmt.Sprintf("(C.%s)(unsafe.Pointer(&%s))", t.Name, name)
	}
	if t.PointerLevel >= 1 {
		return fmt.Sprintf("(%s)(unsafe.Pointer(%s))", t.GoCType(), name)
	}
	return fmt.Sprintf("(%s)(%s)", t.GoCType(), name)
}

// ConvertCToGo converts from the C type to the Go type.
func (t Type) ConvertCToGo(name string) string {
	if t.Name == "GLboolean" {
		return fmt.Sprintf("%s == TRUE", name)
	}
	return fmt.Sprintf("(%s)(%s)", t.GoType(), name)
}

func (t Type) pointers() string {
	return strings.Repeat("*", t.PointerLevel)
}
<commit_msg>Revert "Represent GLsync as uintptr, not unsafe.Pointer"<commit_after>package main

import (
	"fmt"
	"strings"
)

// A Type describes the C and Go type of a function parameter or return value.
type Type struct {
	Name         string // Name of the type without modifiers
	PointerLevel int    // Number of levels of declared indirection to the type
	CDefinition  string // Raw C definition
}

// A Typedef describes a C typedef statement.
type Typedef struct {
	Name        string // Name of the defined type (or included types)
	CDefinition string // Raw C definition
}

func (t Type) String() string {
	return fmt.Sprintf("%s%s [%s]", t.Name, t.pointers(), t.CDefinition)
}

// IsVoid indicates whether this type is the void pseudo-type.
func (t Type) IsVoid() bool {
	return (t.Name == "void" || t.Name == "GLvoid") && t.PointerLevel == 0
}

// IsDebugProc indicates whether this type is a debug callback function pointer.
func (t Type) IsDebugProc() bool {
	return t.Name == "GLDEBUGPROC" || t.Name == "GLDEBUGPROCARB" || t.Name == "GLDEBUGPROCKHR"
}

// CType returns the C definition of the type.
func (t Type) CType() string {
	return t.CDefinition
}

// GoCType returns the Go definition of the C type.
func (t Type) GoCType() string {
	if strings.HasPrefix(t.Name, "struct ") {
		return t.pointers() + "C.struct_" + strings.TrimPrefix(t.Name, "struct ")
	}
	return t.pointers() + "C." + t.Name
}

// GoType returns the Go definition of the type.
func (t Type) GoType() string {
	switch t.Name {
	case "GLbyte":
		return t.pointers() + "int8"
	case "GLubyte":
		return t.pointers() + "uint8"
	case "GLshort":
		return t.pointers() + "int16"
	case "GLushort":
		return t.pointers() + "uint16"
	case "GLint":
		return t.pointers() + "int32"
	case "GLuint":
		return t.pointers() + "uint32"
	case "GLint64", "GLint64EXT":
		return t.pointers() + "int64"
	case "GLuint64", "GLuint64EXT":
		return t.pointers() + "uint64"
	case "GLfloat", "GLclampf":
		return t.pointers() + "float32"
	case "GLdouble", "GLclampd":
		return t.pointers() + "float64"
	case "GLclampx":
		return t.pointers() + "int32"
	case "GLsizei":
		return t.pointers() + "int32"
	case "GLfixed":
		return t.pointers() + "int32"
	case "GLchar", "GLcharARB":
		// Chosen (vs. byte) for compatibility where GL uses GLubyte for strings (e.g., glGetString)
		return t.pointers() + "uint8"
	case "GLboolean":
		return t.pointers() + "bool"
	case "GLenum", "GLbitfield":
		return t.pointers() + "uint32"
	case "GLhalf", "GLhalfNV":
		// Go has no 16-bit floating point type
		return t.pointers() + "uint16"
	case "void", "GLvoid":
		// Type void* could map to either uintptr or unsafe.Pointer but we use the
		// latter because pointers passed from Go to C need to use Go pointer types
		// for the sake of the GC
		if t.PointerLevel == 1 {
			return "unsafe.Pointer"
		} else if t.PointerLevel == 2 {
			return "*unsafe.Pointer"
		}
	case "GLintptr", "GLintptrARB":
		// Type ptrdiff_t should map to an architecture-width Go int
		return t.pointers() + "int"
	case "GLsizeiptr", "GLsizeiptrARB":
		// Same as GLintptr
		return t.pointers() + "int"
	case "GLhandleARB", "GLeglImagesOES", "GLvdpauSurfaceNV":
		// OpenGL pointer types should fit in a pointer-width Go type. No need to
		// use unsafe.Pointer because there is no need for the Go GC to understand
		// that these are pointer types. Moreover on most platforms GLhandleARB is
		// an integer type.
		return t.pointers() + "uintptr"
	case "GLsync":
		return t.pointers() + "unsafe.Pointer"
	case "GLDEBUGPROC", "GLDEBUGPROCARB", "GLDEBUGPROCKHR":
		// Special case mapping to the type defined in debug.tmpl
		return "DebugProc"
	}
	return t.GoCType()
}

// ConvertGoToC returns an expression that converts a variable from the Go type to the C type.
func (t Type) ConvertGoToC(name string) string {
	switch t.Name {
	case "GLboolean":
		if t.PointerLevel == 0 {
			return fmt.Sprintf("(C.GLboolean)(boolToInt(%s))", name)
		}
	case "void", "GLvoid":
		return name
	case "GLDEBUGPROC", "GLDEBUGPROCARB", "GLDEBUGPROCKHR":
		return fmt.Sprintf("(C.%s)(unsafe.Pointer(&%s))", t.Name, name)
	}
	if t.PointerLevel >= 1 {
		return fmt.Sprintf("(%s)(unsafe.Pointer(%s))", t.GoCType(), name)
	}
	return fmt.Sprintf("(%s)(%s)", t.GoCType(), name)
}

// ConvertCToGo converts from the C type to the Go type.
func (t Type) ConvertCToGo(name string) string {
	if t.Name == "GLboolean" {
		return fmt.Sprintf("%s == TRUE", name)
	}
	return fmt.Sprintf("(%s)(%s)", t.GoType(), name)
}

func (t Type) pointers() string {
	return strings.Repeat("*", t.PointerLevel)
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 auth

import (
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestSigner(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type SignerTest struct {}

func init() { RegisterTestSuite(&SignerTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *SignerTest) CallsFunction() {
	ExpectEq("TODO", "")
}

func (t *SignerTest) FunctionReturnsError() {
	ExpectEq("TODO", "")
}

func (t *SignerTest) FunctionReturnsString() {
	ExpectEq("TODO", "")
}

func (t *SignerTest) GoldenTests() {
	ExpectEq("TODO", "")
}
<commit_msg>SignerTest.CallsFunction<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 auth

import (
	"github.com/jacobsa/aws"
	"github.com/jacobsa/aws/s3/http"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestSigner(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type SignerTest struct {}

func init() { RegisterTestSuite(&SignerTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *SignerTest) CallsFunction() {
	// Function
	var stsArg *http.Request
	sts := func(r *http.Request)(string, error) { stsArg = r; return "", nil }

	// Signer
	signer, err := newSigner(sts, aws.AccessKey{})
	AssertEq(nil, err)

	// Call
	req := &http.Request{}
	signer.Sign(req)

	ExpectEq(req, stsArg)
}

func (t *SignerTest) FunctionReturnsError() {
	ExpectEq("TODO", "")
}

func (t *SignerTest) FunctionReturnsString() {
	ExpectEq("TODO", "")
}

func (t *SignerTest) GoldenTests() {
	ExpectEq("TODO", "")
}
<|endoftext|>


<commit_before>// Copyright 2014 Alvaro J. Genial. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ez

import (
	"runtime"
	"testing"
)

type Unit struct {
	fn interface{}
	rs []runner
	T  *testing.T
	B  *testing.B
	tr bool
	br bool
}

type half struct {
	in in
	u  *Unit
}

type runner interface {
	runTest(int, *testing.T)
	runBenchmark(int, *testing.B)
}

func New() *Unit {
	u := &Unit{}
	// FIXME: Sadly, finalizers are not guaranteed to run, so they're of little comfort.
	runtime.SetFinalizer(u, func(u *Unit) {
		if !u.tr && !u.br {
			panic("neither test nor benchmark ran")
		}
	})
	return u
}

func Test(fn interface{}, t *testing.T) *Unit {
	return New().setT(t).Func(fn)
}

func Benchmark(fn interface{}, b *testing.B) *Unit {
	return New().setB(b).Func(fn)
}

func (u *Unit) setT(t *testing.T) *Unit {
	u.T = t
	return u
}

func (u *Unit) setB(b *testing.B) *Unit {
	u.B = b
	return u
}

func (u *Unit) Func(fn interface{}) *Unit {
	u.fn = fn
	return u
}

func (u *Unit) Thru(fn func(*Unit)) *Unit {
	fn(u)
	return u
}

func (u *Unit) Step(fn func()) *Unit {
	u.rs = append(u.rs, Step{fn})
	return u
}

func (u *Unit) Case(in in, out out) *Unit {
	return u.addCase(in, out)
}

func (u *Unit) Cases(cs CaseMap) *Unit {
	for in, out := range cs {
		u = u.addCase(*in, out)
	}
	return u
}

func In(xs ...interface{}) in   { return newIn(xs) }
func Out(xs ...interface{}) out { return newOut(xs) }
func Panic(x interface{}) out   { return newPanic(x) }

func (u *Unit) In(xs ...interface{}) *half  { return &half{newIn(xs), u} }
func (h *half) Out(xs ...interface{}) *Unit { return h.u.addCase(h.in, newOut(xs)) }
func (h *half) Panic(x interface{}) *Unit   { return h.u.addCase(h.in, newPanic(x)) }

func (u *Unit) addCase(in in, out out) *Unit {
	u.rs = append(u.rs, newCase(u.fn, in, out))
	return u
}

func (u *Unit) Run() {
	if u.B == nil && u.T == nil {
		panic("T and B are both nil")
	}
	if u.T != nil {
		u.RunTest(u.T)
	}
	if u.B != nil {
		u.RunBenchmark(u.B)
	}
}

func (u *Unit) RunTest(t *testing.T) {
	if u.tr {
		panic("test already ran")
	}
	u.tr = true

	for i, r := range u.rs {
		r.runTest(i, t)
	}
}

func (u *Unit) RunBenchmark(b *testing.B) {
	if u.br {
		panic("benchmark already ran")
	}
	u.br = true

	for i := 0; i < b.N; i++ {
		for j, r := range u.rs {
			r.runBenchmark(j, b)
		}
	}
}
<commit_msg>Document various Unit methods<commit_after>// Copyright 2014 Alvaro J. Genial. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ez

import (
	"runtime"
	"testing"
)

// A Unit is a specification that can be used for testing and/or benchmarking.
type Unit struct {
	fn interface{}
	rs []runner
	T  *testing.T
	B  *testing.B
	tr bool
	br bool
}

// A half is an incomplete case.
type half struct {
	in in
	u  *Unit
}

// A runner is one of many sequential components of a Unit.
type runner interface {
	runTest(int, *testing.T)
	runBenchmark(int, *testing.B)
}

// New returns a blank Unit.
func New() *Unit {
	u := &Unit{}
	// FIXME: Sadly, finalizers are not guaranteed to run, so they're of little comfort.
	runtime.SetFinalizer(u, func(u *Unit) {
		if !u.tr && !u.br {
			panic("neither test nor benchmark ran")
		}
	})
	return u
}

// Test returns a Unit for testing fn using t.
func Test(fn interface{}, t *testing.T) *Unit {
	return New().setT(t).Func(fn)
}

// Benchmark returns a Unit for benchmarking fn using b.
func Benchmark(fn interface{}, b *testing.B) *Unit {
	return New().setB(b).Func(fn)
}

func (u *Unit) setT(t *testing.T) *Unit {
	u.T = t
	return u
}

func (u *Unit) setB(b *testing.B) *Unit {
	u.B = b
	return u
}

// Func sets fn as the Unit's current function; it can be called more than once.
func (u *Unit) Func(fn interface{}) *Unit {
	u.fn = fn
	return u
}

// Thru applies fn to the Unit, which is useful to combine or repeat common Unit components.
func (u *Unit) Thru(fn func(*Unit)) *Unit {
	fn(u)
	return u
}

// Step adds fn to the Unit as a Step.
func (u *Unit) Step(fn func()) *Unit {
	u.rs = append(u.rs, Step{fn})
	return u
}

// Case adds in & out (plus the current function) as a Case to the Unit.
func (u *Unit) Case(in in, out out) *Unit {
	return u.addCase(in, out)
}

// Cases adds every in/out pair in the CaseMap (plus the current function) as a Case to the Unit.
func (u *Unit) Cases(cs CaseMap) *Unit {
	for in, out := range cs {
		u = u.addCase(*in, out)
	}
	return u
}

func In(xs ...interface{}) in   { return newIn(xs) }
func Out(xs ...interface{}) out { return newOut(xs) }
func Panic(x interface{}) out   { return newPanic(x) }

// In begins a Case with xs as inputs.
func (u *Unit) In(xs ...interface{}) *half { return &half{newIn(xs), u} }

// Out completes a Case with xs as outputs and adds it to the Unit.
func (h *half) Out(xs ...interface{}) *Unit { return h.u.addCase(h.in, newOut(xs)) }

// Panic completes a Case that must panic with x and adds it to the Unit.
func (h *half) Panic(x interface{}) *Unit { return h.u.addCase(h.in, newPanic(x)) }

func (u *Unit) addCase(in in, out out) *Unit {
	u.rs = append(u.rs, newCase(u.fn, in, out))
	return u
}

// Run runs the Unit as a test and/or benchmark, depending on whether T and/or B are set.
func (u *Unit) Run() {
	if u.B == nil && u.T == nil {
		panic("T and B are both nil")
	}
	if u.T != nil {
		u.RunTest(u.T)
	}
	if u.B != nil {
		u.RunBenchmark(u.B)
	}
}

// RunTest runs the Unit as a test using t.
func (u *Unit) RunTest(t *testing.T) {
	if u.tr {
		panic("test already ran")
	}
	u.tr = true

	for i, r := range u.rs {
		r.runTest(i, t)
	}
}

// RunBenchmark runs the Unit as a benchmark using b.
func (u *Unit) RunBenchmark(b *testing.B) {
	if u.br {
		panic("benchmark already ran")
	}
	u.br = true

	for i := 0; i < b.N; i++ {
		for j, r := range u.rs {
			r.runBenchmark(j, b)
		}
	}
}
<|endoftext|>


<commit_before>package main

const (
	groupPlayer = iota
	groupEnemy
)

type unitID uint64

type unit struct {
	id         unitID
	playerName string
	unitName   string
	group      uint8
	seat       uint8
	ur         *unitResource
	us         *unitStatistics
	um         *unitModification
	operators  map[operator]bool
	dispatcher *eventDispatcher
	game       *game
}

type unitResource struct {
	health int32
	mana   int32
}

// newUnit initializes a unit
func newUnit(g *game) *unit {
	return &unit{
		us:         &unitStatistics{},
		um:         &unitModification{},
		operators:  make(map[operator]bool),
		dispatcher: newEventDispatcher(),
		game:       g,
	}
}

func (u *unit) now() gameTime {
	return u.game.now()
}

func (u *unit) publish(m message) {
	u.game.publish(m)
}

func (u *unit) isAlive() bool {
	return u.ur.health > 0
}

func (u *unit) isDead() bool {
	return u.ur.health <= 0
}

func (u *unit) health() int32 {
	return u.ur.health
}

func (u *unit) maxHealth() int32 {
	return u.us.health
}

func (u *unit) healthRegeneration() int32 {
	return u.us.healthRegeneration
}

func (u *unit) mana() int32 {
	return u.ur.mana
}

func (u *unit) maxMana() int32 {
	return u.us.mana
}

func (u *unit) manaRegeneration() int32 {
	return u.us.manaRegeneration
}

func (u *unit) armor() int32 {
	return u.us.armor + u.um.armor
}

func (u *unit) magicResistance() int32 {
	return u.us.magicResistance + u.um.magicResistance
}

func (u *unit) criticalStrikeChance() int32 {
	return u.us.criticalStrikeChance + u.um.criticalStrikeChance
}

func (u *unit) criticalStrikeDamage() int32 {
	return u.us.criticalStrikeDamage + u.um.criticalStrikeDamage
}

func (u *unit) cooldownReduction() int32 {
	return u.us.cooldownReduction + u.um.cooldownReduction
}

func (u *unit) threatFactor() int32 {
	return u.us.threatFactor + u.um.threatFactor
}

// addHealth adds health and returns before/after health
func (u *unit) addHealth(d int32) (before, after int32) {
	before := u.health()
	after := u.health() + d
	if after < 0 {
		after = 0
	}
	if after > u.maxHealth() {
		after = u.maxHealth()
	}
	u.ur.health = after
	return
}

// addMana adds mana and returns before/after mana
func (u *unit) addMana(d int32) (before, after int32) {
	before := u.mana()
	after := u.mana() + d
	if after < 0 {
		after = 0
	}
	if after > u.maxMana() {
		after = u.maxMana()
	}
	u.ur.mana = after
	return
}

// attachOperator adds the operator
func (u *unit) attachOperator(o operator) {
	u.operators[o] = true
	o.onAttach()
}

// detachOperator removes the operator
func (u *unit) detachOperator(o operator) {
	delete(u.operators, o)
	o.onDetach()
}

// addEventHandler registers the eventHandler
func (u *unit) addEventHandler(h eventHandler, e event) {
	u.dispatcher.addEventHandler(h, e)
}

// addEventHandler unregisters the eventHandler
func (u *unit) removeEventHandler(h eventHandler, e event) {
	u.dispatcher.removeEventHandler(h, e)
}

// triggerEvent triggers the event
func (u *unit) triggerEvent(e event) {
	u.dispatcher.triggerEvent(e)
}

// gameTick triggers onComplete iff the operator is completed
func (u *unit) gameTick() {
	if u.isDead() {
		return
	}
	u.triggerEvent(eventGameTick)
}

// statsTick performs regeneration and triggers statsTick
func (u *unit) statsTick() {
	if u.isDead() {
		return
	}
	u.performHealthRegeneration()
	u.performManaRegeneration()
	u.triggerEvent(eventStatsTick)
}

// performHealthRegeneration performs health regeneration
func (u *unit) performHealthRegeneration() {
	u.addHealth(u.healthRegeneration())
	u.publish(message{
		// TODO pack message
		t: outHealthReg,
	})
}

// performManaRegeneration performs mana regeneration
func (u *unit) performManaRegeneration() {
	u.addMana(u.manaRegeneration())
	u.publish(message{
		// TODO pack message
		t: outManaReg,
	})
}

// updateModification updates the unitModification
func (u *unit) updateModification() {
	u.um = &unitModification{}
	for o := range u.operators {
		if _, ok := o.(*modifier); ok {
			u.um.add(o.(*modifier).um)
		}
	}
	u.triggerEvent(eventStats)
}
<commit_msg>Fix syntax bugs<commit_after>package main

const (
	groupPlayer = iota
	groupEnemy
)

type unitID uint64

type unit struct {
	id         unitID
	playerName string
	unitName   string
	group      uint8
	seat       uint8
	ur         *unitResource
	us         *unitStatistics
	um         *unitModification
	operators  map[operator]bool
	dispatcher *eventDispatcher
	game       *game
}

type unitResource struct {
	health int32
	mana   int32
}

// newUnit initializes a unit
func newUnit(g *game) *unit {
	return &unit{
		us:         &unitStatistics{},
		um:         &unitModification{},
		operators:  make(map[operator]bool),
		dispatcher: newEventDispatcher(),
		game:       g,
	}
}

func (u *unit) now() gameTime {
	return u.game.now()
}

func (u *unit) publish(m message) {
	u.game.publish(m)
}

func (u *unit) isAlive() bool {
	return u.ur.health > 0
}

func (u *unit) isDead() bool {
	return u.ur.health <= 0
}

func (u *unit) health() int32 {
	return u.ur.health
}

func (u *unit) maxHealth() int32 {
	return u.us.health
}

func (u *unit) healthRegeneration() int32 {
	return u.us.healthRegeneration
}

func (u *unit) mana() int32 {
	return u.ur.mana
}

func (u *unit) maxMana() int32 {
	return u.us.mana
}

func (u *unit) manaRegeneration() int32 {
	return u.us.manaRegeneration
}

func (u *unit) armor() int32 {
	return u.us.armor + u.um.armor
}

func (u *unit) magicResistance() int32 {
	return u.us.magicResistance + u.um.magicResistance
}

func (u *unit) criticalStrikeChance() int32 {
	return u.us.criticalStrikeChance + u.um.criticalStrikeChance
}

func (u *unit) criticalStrikeDamage() int32 {
	return u.us.criticalStrikeDamage + u.um.criticalStrikeDamage
}

func (u *unit) cooldownReduction() int32 {
	return u.us.cooldownReduction + u.um.cooldownReduction
}

func (u *unit) threatFactor() int32 {
	return u.us.threatFactor + u.um.threatFactor
}

// addHealth adds health and returns before/after health
func (u *unit) addHealth(d int32) (before, after int32) {
	before = u.health()
	after = u.health() + d
	if after < 0 {
		after = 0
	}
	if after > u.maxHealth() {
		after = u.maxHealth()
	}
	u.ur.health = after
	return
}

// addMana adds mana and returns before/after mana
func (u *unit) addMana(d int32) (before, after int32) {
	before = u.mana()
	after = u.mana() + d
	if after < 0 {
		after = 0
	}
	if after > u.maxMana() {
		after = u.maxMana()
	}
	u.ur.mana = after
	return
}

// attachOperator adds the operator
func (u *unit) attachOperator(o operator) {
	u.operators[o] = true
	o.onAttach()
}

// detachOperator removes the operator
func (u *unit) detachOperator(o operator) {
	delete(u.operators, o)
	o.onDetach()
}

// addEventHandler registers the eventHandler
func (u *unit) addEventHandler(h eventHandler, e event) {
	u.dispatcher.addEventHandler(h, e)
}

// addEventHandler unregisters the eventHandler
func (u *unit) removeEventHandler(h eventHandler, e event) {
	u.dispatcher.removeEventHandler(h, e)
}

// triggerEvent triggers the event
func (u *unit) triggerEvent(e event) {
	u.dispatcher.triggerEvent(e)
}

// gameTick triggers onComplete iff the operator is completed
func (u *unit) gameTick() {
	if u.isDead() {
		return
	}
	u.triggerEvent(eventGameTick)
}

// statsTick performs regeneration and triggers statsTick
func (u *unit) statsTick() {
	if u.isDead() {
		return
	}
	u.performHealthRegeneration()
	u.performManaRegeneration()
	u.triggerEvent(eventStatsTick)
}

// performHealthRegeneration performs health regeneration
func (u *unit) performHealthRegeneration() {
	u.addHealth(u.healthRegeneration())
	u.publish(message{
		// TODO pack message
		t: outHealthReg,
	})
}

// performManaRegeneration performs mana regeneration
func (u *unit) performManaRegeneration() {
	u.addMana(u.manaRegeneration())
	u.publish(message{
		// TODO pack message
		t: outManaReg,
	})
}

// updateModification updates the unitModification
func (u *unit) updateModification() {
	u.um = &unitModification{}
	for o := range u.operators {
		if _, ok := o.(*modifier); ok {
			u.um.add(o.(*modifier).um)
		}
	}
	u.triggerEvent(eventStats)
}
<|endoftext|>


<commit_before>package venom

import (
	"time"
)

var (
	DefaultTimeFormat = time.RFC3339
)

//
// time.Time
//
type timeValue time.Time

func newTimeValue(val time.Time, p *time.Time) *timeValue {
	*p = val
	return (*timeValue)(p)
}

func (v *timeValue) Set(s string) error {
	val, err := time.Parse(s, DefaultTimeFormat)
	*v = timeValue(val)
	return err
}

func (v *timeValue) Type() string {
	return "time"
}

func (v *timeValue) String() string {
	return time.Time(*v).Format(DefaultTimeFormat)
}

//
// time.Duration
//
type durationValue time.Duration

func newDurationValue(val time.Duration, p *time.Duration) *durationValue {
	*p = val
	return (*durationValue)(p)
}

func (v *durationValue) Set(s string) error {
	val, err := time.ParseDuration(s)
	*v = durationValue(val)
	return err
}

func (v *durationValue) Type() string {
	return "duration"
}

func (v *durationValue) String() string {
	return time.Duration(*v).String()
}
<commit_msg>Moar docs<commit_after>//
// Here we implement extra flags to extend pflag/viper binding.
//
// https://godoc.org/github.com/spf13/pflag#Value
//
// type Value interface {
//     String() string
//     Set(string) error
//     Type() string
// }
//

package venom

import (
	"time"
)

var (
	DefaultTimeFormat = time.RFC3339
)

//
// time.Time
//
type timeValue time.Time

func newTimeValue(val time.Time, p *time.Time) *timeValue {
	*p = val
	return (*timeValue)(p)
}

func (v *timeValue) Set(s string) error {
	val, err := time.Parse(s, DefaultTimeFormat)
	*v = timeValue(val)
	return err
}

func (v *timeValue) Type() string {
	return "time"
}

func (v *timeValue) String() string {
	return time.Time(*v).Format(DefaultTimeFormat)
}

//
// time.Duration
//
type durationValue time.Duration

func newDurationValue(val time.Duration, p *time.Duration) *durationValue {
	*p = val
	return (*durationValue)(p)
}

func (v *durationValue) Set(s string) error {
	val, err := time.ParseDuration(s)
	*v = durationValue(val)
	return err
}

func (v *durationValue) Type() string {
	return "duration"
}

func (v *durationValue) String() string {
	return time.Duration(*v).String()
}
<|endoftext|>


<commit_before>package wrp

import (
	"bytes"
	"sync"
	"testing"
)

type pooledEncoder struct {
	encoder Encoder
	buffer  *bytes.Buffer
}

func pooledEncoderFactory(format Format) func() interface{} {
	return func() interface{} {
		return &pooledEncoder{
			encoder: NewEncoder(nil, format),
			buffer:  new(bytes.Buffer),
		}
	}
}

var (
	testMessage = Message{
		Source:          "http://source.comcast.net:9090/test",
		Destination:     "mac:112233445566",
		TransactionUUID: "as;ldkfjakdljfaskdjfaskdjf",
		Payload:         []byte("ah, some lovely payload here!"),
	}

	encoderPools = []sync.Pool{
		sync.Pool{
			New: pooledEncoderFactory(JSON),
		},
		sync.Pool{
			New: pooledEncoderFactory(Msgpack),
		},
	}
)

func benchmarkCreateEncoderOnTheFly(b *testing.B, format Format) {
	for repeat := 0; repeat < b.N; repeat++ {
		var (
			buffer  = new(bytes.Buffer)
			encoder = NewEncoder(buffer, format)
		)

		encoder.Encode(testMessage)
	}
}

func BenchmarkCreateEncoderOnTheFly(b *testing.B) {
	for _, format := range []Format{Msgpack, JSON} {
		b.Run(
			format.String(),
			func(b *testing.B) {
				benchmarkCreateEncoderOnTheFly(b, format)
			},
		)
	}
}

func benchmarkPooledEncoder(b *testing.B, format Format) {
	for repeat := 0; repeat < b.N; repeat++ {
		pooled := encoderPools[format].Get().(*pooledEncoder)
		pooled.buffer.Reset()
		pooled.encoder.Reset(pooled.buffer)
		pooled.encoder.Encode(testMessage)

		encoderPools[format].Put(pooled)
	}
}

func BenchmarkPooledEncoder(b *testing.B) {
	for _, format := range []Format{Msgpack, JSON} {
		b.Run(
			format.String(),
			func(b *testing.B) {
				benchmarkPooledEncoder(b, format)
			},
		)
	}
}
<commit_msg>Added concurrency to the benchmarks<commit_after>package wrp

import (
	"bytes"
	"fmt"
	"sync"
	"testing"
)

type pooledEncoder struct {
	encoder Encoder
	buffer  *bytes.Buffer
}

func pooledEncoderFactory(format Format) func() interface{} {
	return func() interface{} {
		return &pooledEncoder{
			encoder: NewEncoder(nil, format),
			buffer:  new(bytes.Buffer),
		}
	}
}

var (
	testMessage = Message{
		Source:          "http://source.comcast.net:9090/test",
		Destination:     "mac:112233445566",
		TransactionUUID: "as;ldkfjakdljfaskdjfaskdjf",
		Payload:         []byte("ah, some lovely payload here!"),
	}

	encoderPools = []sync.Pool{
		sync.Pool{
			New: pooledEncoderFactory(JSON),
		},
		sync.Pool{
			New: pooledEncoderFactory(Msgpack),
		},
	}
)

func benchmarkCreateEncoderOnTheFly(b *testing.B, format Format, routines int) {
	var (
		startingLine = make(chan struct{})
		waitGroup    = new(sync.WaitGroup)
	)

	waitGroup.Add(routines)
	for spawn := 0; spawn < routines; spawn++ {
		go func() {
			defer waitGroup.Done()
			<-startingLine

			for repeat := 0; repeat < b.N; repeat++ {
				var (
					buffer  = new(bytes.Buffer)
					encoder = NewEncoder(buffer, format)
				)

				encoder.Encode(testMessage)
			}
		}()
	}

	b.ResetTimer()
	close(startingLine)
	waitGroup.Wait()
}

func BenchmarkCreateEncoderOnTheFly(b *testing.B) {
	for _, format := range []Format{Msgpack, JSON} {
		for _, routines := range []int{1, 10, 100} {
			b.Run(
				fmt.Sprintf("%s/routines=%d", format, routines),
				func(b *testing.B) { benchmarkCreateEncoderOnTheFly(b, format, routines) },
			)
		}
	}
}

func benchmarkPooledEncoder(b *testing.B, format Format, routines int) {
	var (
		startingLine = make(chan struct{})
		waitGroup    = new(sync.WaitGroup)
	)

	waitGroup.Add(routines)
	for spawn := 0; spawn < routines; spawn++ {
		go func() {
			defer waitGroup.Done()
			<-startingLine

			for repeat := 0; repeat < b.N; repeat++ {
				pooled := encoderPools[format].Get().(*pooledEncoder)
				pooled.buffer.Reset()
				pooled.encoder.Reset(pooled.buffer)
				pooled.encoder.Encode(testMessage)

				encoderPools[format].Put(pooled)
			}
		}()
	}

	b.ResetTimer()
	close(startingLine)
	waitGroup.Wait()
}

func BenchmarkPooledEncoder(b *testing.B) {
	for _, format := range []Format{Msgpack, JSON} {
		for _, routines := range []int{1, 10, 100} {
			b.Run(
				fmt.Sprintf("%s/routines=%d", format, routines),
				func(b *testing.B) { benchmarkPooledEncoder(b, format, routines) },
			)
		}
	}
}
<|endoftext|>


<commit_before>// Package fonts provides a cross-platform interface to list and load font data
package fonts

import "io"

// Font holds the name of a font and an optional string indicating the font's source
type Font struct {
	Name   string
	Source string
}

// List the available fonts
func List() ([]Font, error) {
	return listFonts()
}

// Load attempts to load font file data given a font names
func Load(fontNames ...string) (io.Reader, error) {
	for _, fontName := range fontNames {
		b, e := loadFont(fontName)
		if e == nil {
			return b, e
		}
	}
	if len(fontNames) > 1 {
		return nil, errNoneFoundPlural
	}
	return nil, errNoneFound
}

// Load attempts to load the font's data from its Name
func (f Font) Load() (io.Reader, error) {
	return Load(f.Name)
}

// ValidExtensions is the list of file extensions to consider font files
var ValidExtensions = []string{"ttf", "otf"}
<commit_msg>Fix small typo<commit_after>// Package fonts provides a cross-platform interface to list and load font data
package fonts

import "io"

// Font holds the name of a font and an optional string indicating the font's source
type Font struct {
	Name   string
	Source string
}

// List the available fonts
func List() ([]Font, error) {
	return listFonts()
}

// Load attempts to load font file data given font names
func Load(fontNames ...string) (io.Reader, error) {
	for _, fontName := range fontNames {
		b, e := loadFont(fontName)
		if e == nil {
			return b, e
		}
	}
	if len(fontNames) > 1 {
		return nil, errNoneFoundPlural
	}
	return nil, errNoneFound
}

// Load attempts to load the font's data from its Name
func (f Font) Load() (io.Reader, error) {
	return Load(f.Name)
}

// ValidExtensions is the list of file extensions to consider font files
var ValidExtensions = []string{"ttf", "otf"}
<|endoftext|>


<commit_before>package ws

import (
	"bytes"
	"encoding/binary"
	"math/rand"
)

// Constants defined by specification.
const (
	// All control frames MUST have a payload length of 125 bytes or less and MUST NOT be fragmented.
	MaxControlFramePayloadSize = 125
)

// OpCode represents operation code.
type OpCode byte

// Operation codes defined by specification.
// See https://tools.ietf.org/html/rfc6455#section-5.2
const (
	OpContinuation OpCode = 0x0
	OpText         OpCode = 0x1
	OpBinary       OpCode = 0x2
	OpClose        OpCode = 0x8
	OpPing         OpCode = 0x9
	OpPong         OpCode = 0xa
)

// IsControl checks whether the c is control operation code.
// See https://tools.ietf.org/html/rfc6455#section-5.5
func (c OpCode) IsControl() bool {
	// RFC6455: Control frames are identified by opcodes where
	// the most significant bit of the opcode is 1.
	//
	// Note that OpCode is only 4 bit length.
	return c&0x8 != 0
}

// IsData checks whether the c is data operation code.
// See https://tools.ietf.org/html/rfc6455#section-5.6
func (c OpCode) IsData() bool {
	// RFC6455: Data frames (e.g., non-control frames) are identified by opcodes
	// where the most significant bit of the opcode is 0.
	//
	// Note that OpCode is only 4 bit length.
	return c&0x8 == 0
}

// IsReserved checks whether the c is reserved operation code.
// See https://tools.ietf.org/html/rfc6455#section-5.2
func (c OpCode) IsReserved() bool {
	// RFC6455:
	// %x3-7 are reserved for further non-control frames
	// %xB-F are reserved for further control frames
	return (0x3 <= c && c <= 0x7) || (0xb <= c && c <= 0xf)
}

// StatusCode represents the encoded reason for closure of websocket connection.
//
// There are few helper methods on StatusCode that helps to define a range in
// which given code is lay in. accordingly to ranges defined in specification.
//
// See https://tools.ietf.org/html/rfc6455#section-7.4
type StatusCode uint16

// StatusCodeRange describes range of StatusCode values.
type StatusCodeRange struct {
	Min, Max StatusCode
}

// Status code ranges defined by specification.
// See https://tools.ietf.org/html/rfc6455#section-7.4.2
var (
	StatusRangeNotInUse    = StatusCodeRange{0, 999}
	StatusRangeProtocol    = StatusCodeRange{1000, 2999}
	StatusRangeApplication = StatusCodeRange{3000, 3999}
	StatusRangePrivate     = StatusCodeRange{4000, 4999}
)

// Status codes defined by specification.
// See https://tools.ietf.org/html/rfc6455#section-7.4.1
const (
	StatusNormalClosure           StatusCode = 1000
	StatusGoingAway               StatusCode = 1001
	StatusProtocolError           StatusCode = 1002
	StatusUnsupportedData         StatusCode = 1003
	StatusNoMeaningYet            StatusCode = 1004
	StatusInvalidFramePayloadData StatusCode = 1007
	StatusPolicyViolation         StatusCode = 1008
	StatusMessageTooBig           StatusCode = 1009
	StatusMandatoryExt            StatusCode = 1010
	StatusInternalServerError     StatusCode = 1011
	StatusTLSHandshake            StatusCode = 1015

	// StatusAbnormalClosure is a special code designated for use in
	// applications.
	StatusAbnormalClosure StatusCode = 1006

	// StatusNoStatusRcvd is a special code designated for use in applications.
	StatusNoStatusRcvd StatusCode = 1005
)

// In reports whether the code is defined in given range.
func (s StatusCode) In(r StatusCodeRange) bool {
	return r.Min <= s && s <= r.Max
}

// Empty reports whether the code is empty.
// Empty code has no any meaning neither app level codes nor other.
// This method is useful just to check that code is golang default value 0.
func (s StatusCode) Empty() bool {
	return s == 0
}

// IsNotUsed reports whether the code is predefined in not used range.
func (s StatusCode) IsNotUsed() bool {
	return s.In(StatusRangeNotInUse)
}

// IsApplicationSpec reports whether the code should be defined by
// application, framework or libraries specification.
func (s StatusCode) IsApplicationSpec() bool {
	return s.In(StatusRangeApplication)
}

// IsPrivateSpec reports whether the code should be defined privately.
func (s StatusCode) IsPrivateSpec() bool {
	return s.In(StatusRangePrivate)
}

// IsProtocolSpec reports whether the code should be defined by protocol specification.
func (s StatusCode) IsProtocolSpec() bool {
	return s.In(StatusRangeProtocol)
}

// IsProtocolDefined reports whether the code is already defined by protocol specification.
func (s StatusCode) IsProtocolDefined() bool {
	switch s {
	case StatusNormalClosure,
		StatusGoingAway,
		StatusProtocolError,
		StatusUnsupportedData,
		StatusInvalidFramePayloadData,
		StatusPolicyViolation,
		StatusMessageTooBig,
		StatusMandatoryExt,
		StatusInternalServerError,
		StatusNoStatusRcvd,
		StatusAbnormalClosure,
		StatusTLSHandshake:
		return true
	}
	return false
}

// IsProtocolReserved reports whether the code is defined by protocol specification
// to be reserved only for application usage purpose.
func (s StatusCode) IsProtocolReserved() bool {
	switch s {
	// [RFC6455]: {1005,1006,1015} is a reserved value and MUST NOT be set as a status code in a
	// Close control frame by an endpoint.
	case StatusNoStatusRcvd, StatusAbnormalClosure, StatusTLSHandshake:
		return true
	default:
		return false
	}
}

// Compiled control frames for common use cases.
// For construct-serialize optimizations.
var (
	CompiledPing  = MustCompileFrame(NewPingFrame(nil))
	CompiledPong  = MustCompileFrame(NewPongFrame(nil))
	CompiledClose = MustCompileFrame(NewCloseFrame(nil))

	CompiledCloseNormalClosure           = MustCompileFrame(closeFrameNormalClosure)
	CompiledCloseGoingAway               = MustCompileFrame(closeFrameGoingAway)
	CompiledCloseProtocolError           = MustCompileFrame(closeFrameProtocolError)
	CompiledCloseUnsupportedData         = MustCompileFrame(closeFrameUnsupportedData)
	CompiledCloseNoMeaningYet            = MustCompileFrame(closeFrameNoMeaningYet)
	CompiledCloseInvalidFramePayloadData = MustCompileFrame(closeFrameInvalidFramePayloadData)
	CompiledClosePolicyViolation         = MustCompileFrame(closeFramePolicyViolation)
	CompiledCloseMessageTooBig           = MustCompileFrame(closeFrameMessageTooBig)
	CompiledCloseMandatoryExt            = MustCompileFrame(closeFrameMandatoryExt)
	CompiledCloseInternalServerError     = MustCompileFrame(closeFrameInternalServerError)
	CompiledCloseTLSHandshake            = MustCompileFrame(closeFrameTLSHandshake)
)

// Header represents websocket frame header.
// See https://tools.ietf.org/html/rfc6455#section-5.2
type Header struct {
	Fin    bool
	Rsv    byte
	OpCode OpCode
	Masked bool
	Mask   [4]byte
	Length int64
}

// Rsv1 reports whether the header has first rsv bit set.
func (h Header) Rsv1() bool { return h.Rsv&bit5 != 0 }

// Rsv2 reports whether the header has second rsv bit set.
func (h Header) Rsv2() bool { return h.Rsv&bit6 != 0 }

// Rsv3 reports whether the header has third rsv bit set.
func (h Header) Rsv3() bool { return h.Rsv&bit7 != 0 }

// Frame represents websocket frame.
// See https://tools.ietf.org/html/rfc6455#section-5.2
type Frame struct {
	Header  Header
	Payload []byte
}

// NewFrame creates frame with given operation code,
// flag of completeness and payload bytes.
func NewFrame(op OpCode, fin bool, p []byte) Frame {
	return Frame{
		Header: Header{
			Fin:    fin,
			OpCode: op,
			Length: int64(len(p)),
		},
		Payload: p,
	}
}

// NewTextFrame creates text frame with p as payload.
// Note that p is not copied.
func NewTextFrame(p []byte) Frame {
	return NewFrame(OpText, true, p)
}

// NewBinaryFrame creates binary frame with p as payload.
// Note that p is not copied.
func NewBinaryFrame(p []byte) Frame {
	return NewFrame(OpBinary, true, p)
}

// NewPingFrame creates ping frame with p as payload.
// Note that p is not copied.
// Note that p must have length of MaxControlFramePayloadSize bytes or less due
// to RFC.
func NewPingFrame(p []byte) Frame {
	return NewFrame(OpPing, true, p)
}

// NewPongFrame creates pong frame with p as payload.
// Note that p is not copied.
// Note that p must have length of MaxControlFramePayloadSize bytes or less due
// to RFC.
func NewPongFrame(p []byte) Frame {
	return NewFrame(OpPong, true, p)
}

// NewCloseFrame creates close frame with given close body.
// Note that p is not copied.
// Note that p must have length of MaxControlFramePayloadSize bytes or less due
// to RFC.
func NewCloseFrame(p []byte) Frame {
	return NewFrame(OpClose, true, p)
}

// NewCloseFrameBody encodes a closure code and a reason into a binary
// representation.
//
// It returns slice which is at most MaxControlFramePayloadSize bytes length.
// If the reason is too big it will be cropped to fit the limit defined by the
// spec.
//
// See https://tools.ietf.org/html/rfc6455#section-5.5
func NewCloseFrameBody(code StatusCode, reason string) []byte {
	n := min(2+len(reason), MaxControlFramePayloadSize)
	p := make([]byte, n)

	crop := min(MaxControlFramePayloadSize-2, len(reason))
	PutCloseFrameBody(p, code, reason[:crop])

	return p
}

// PutCloseFrameBody encodes code and reason into buf.
//
// It will panic if the buffer is too small to accommodate a code or a reason.
//
// PutCloseFrameBody does not check buffer to be RFC compliant, but note that
// by RFC it must be at most MaxControlFramePayloadSize.
func PutCloseFrameBody(p []byte, code StatusCode, reason string) {
	_ = p[1+len(reason)]
	binary.BigEndian.PutUint16(p, uint16(code))
	copy(p[2:], reason)
}

// MaskFrame masks frame and returns frame with masked payload and Mask header's field set.
// Note that it copies f payload to prevent collisions.
// For less allocations you could use MaskFrameInPlace or construct frame manually.
func MaskFrame(f Frame) Frame {
	return MaskFrameWith(f, NewMask())
}

// MaskFrameWith masks frame with given mask and returns frame
// with masked payload and Mask header's field set.
// Note that it copies f payload to prevent collisions.
// For less allocations you could use MaskFrameInPlaceWith or construct frame manually.
func MaskFrameWith(f Frame, mask [4]byte) Frame {
	// TODO(gobwas): check CopyCipher ws copy() Cipher().
	p := make([]byte, len(f.Payload))
	copy(p, f.Payload)
	f.Payload = p
	return MaskFrameInPlaceWith(f, mask)
}

// MaskFrameInPlace masks frame and returns frame with masked payload and Mask
// header's field set.
// Note that it applies xor cipher to f.Payload without copying, that is, it
// modifies f.Payload inplace.
func MaskFrameInPlace(f Frame) Frame {
	return MaskFrameInPlaceWith(f, NewMask())
}

// MaskFrameInPlaceWith masks frame with given mask and returns frame
// with masked payload and Mask header's field set.
// Note that it applies xor cipher to f.Payload without copying, that is, it
// modifies f.Payload inplace.
func MaskFrameInPlaceWith(f Frame, m [4]byte) Frame {
	f.Header.Masked = true
	f.Header.Mask = m
	Cipher(f.Payload, m, 0)
	return f
}

// NewMask creates new random mask.
func NewMask() (ret [4]byte) {
	binary.BigEndian.PutUint32(ret[:], rand.Uint32())
	return
}

// CompileFrame returns byte representation of given frame.
// In terms of memory consumption it is useful to precompile static frames
// which are often used.
func CompileFrame(f Frame) (bts []byte, err error) {
	buf := bytes.NewBuffer(make([]byte, 0, 16))
	err = WriteFrame(buf, f)
	bts = buf.Bytes()
	return
}

// MustCompileFrame is like CompileFrame but panics if frame cannot be encoded.
func MustCompileFrame(f Frame) []byte {
	bts, err := CompileFrame(f)
	if err != nil {
		panic(err)
	}
	return bts
}

// Rsv creates rsv byte representation.
func Rsv(r1, r2, r3 bool) (rsv byte) {
	if r1 {
		rsv |= bit5
	}
	if r2 {
		rsv |= bit6
	}
	if r3 {
		rsv |= bit7
	}
	return rsv
}

func makeCloseFrame(code StatusCode, reason string) Frame {
	return NewCloseFrame(NewCloseFrameBody(
		code, reason,
	))
}

var (
	closeFrameNormalClosure           = makeCloseFrame(StatusNormalClosure, "")
	closeFrameGoingAway               = makeCloseFrame(StatusGoingAway, "")
	closeFrameProtocolError           = makeCloseFrame(StatusProtocolError, "")
	closeFrameUnsupportedData         = makeCloseFrame(StatusUnsupportedData, "")
	closeFrameNoMeaningYet            = makeCloseFrame(StatusNoMeaningYet, "")
	closeFrameInvalidFramePayloadData = makeCloseFrame(StatusInvalidFramePayloadData, "")
	closeFramePolicyViolation         = makeCloseFrame(StatusPolicyViolation, "")
	closeFrameMessageTooBig           = makeCloseFrame(StatusMessageTooBig, "")
	closeFrameMandatoryExt            = makeCloseFrame(StatusMandatoryExt, "")
	closeFrameInternalServerError     = makeCloseFrame(StatusInternalServerError, "")
	closeFrameTLSHandshake            = makeCloseFrame(StatusTLSHandshake, "")
)
<commit_msg>ws: wrap comment<commit_after>package ws

import (
	"bytes"
	"encoding/binary"
	"math/rand"
)

// Constants defined by specification.
const (
	// All control frames MUST have a payload length of 125 bytes or less and MUST NOT be fragmented.
	MaxControlFramePayloadSize = 125
)

// OpCode represents operation code.
type OpCode byte

// Operation codes defined by specification.
// See https://tools.ietf.org/html/rfc6455#section-5.2
const (
	OpContinuation OpCode = 0x0
	OpText         OpCode = 0x1
	OpBinary       OpCode = 0x2
	OpClose        OpCode = 0x8
	OpPing         OpCode = 0x9
	OpPong         OpCode = 0xa
)

// IsControl checks whether the c is control operation code.
// See https://tools.ietf.org/html/rfc6455#section-5.5
func (c OpCode) IsControl() bool {
	// RFC6455: Control frames are identified by opcodes where
	// the most significant bit of the opcode is 1.
	//
	// Note that OpCode is only 4 bit length.
	return c&0x8 != 0
}

// IsData checks whether the c is data operation code.
// See https://tools.ietf.org/html/rfc6455#section-5.6
func (c OpCode) IsData() bool {
	// RFC6455: Data frames (e.g., non-control frames) are identified by opcodes
	// where the most significant bit of the opcode is 0.
	//
	// Note that OpCode is only 4 bit length.
	return c&0x8 == 0
}

// IsReserved checks whether the c is reserved operation code.
// See https://tools.ietf.org/html/rfc6455#section-5.2
func (c OpCode) IsReserved() bool {
	// RFC6455:
	// %x3-7 are reserved for further non-control frames
	// %xB-F are reserved for further control frames
	return (0x3 <= c && c <= 0x7) || (0xb <= c && c <= 0xf)
}

// StatusCode represents the encoded reason for closure of websocket connection.
//
// There are few helper methods on StatusCode that helps to define a range in
// which given code is lay in. accordingly to ranges defined in specification.
//
// See https://tools.ietf.org/html/rfc6455#section-7.4
type StatusCode uint16

// StatusCodeRange describes range of StatusCode values.
type StatusCodeRange struct {
	Min, Max StatusCode
}

// Status code ranges defined by specification.
// See https://tools.ietf.org/html/rfc6455#section-7.4.2
var (
	StatusRangeNotInUse    = StatusCodeRange{0, 999}
	StatusRangeProtocol    = StatusCodeRange{1000, 2999}
	StatusRangeApplication = StatusCodeRange{3000, 3999}
	StatusRangePrivate     = StatusCodeRange{4000, 4999}
)

// Status codes defined by specification.
// See https://tools.ietf.org/html/rfc6455#section-7.4.1
const (
	StatusNormalClosure           StatusCode = 1000
	StatusGoingAway               StatusCode = 1001
	StatusProtocolError           StatusCode = 1002
	StatusUnsupportedData         StatusCode = 1003
	StatusNoMeaningYet            StatusCode = 1004
	StatusInvalidFramePayloadData StatusCode = 1007
	StatusPolicyViolation         StatusCode = 1008
	StatusMessageTooBig           StatusCode = 1009
	StatusMandatoryExt            StatusCode = 1010
	StatusInternalServerError     StatusCode = 1011
	StatusTLSHandshake            StatusCode = 1015

	// StatusAbnormalClosure is a special code designated for use in
	// applications.
	StatusAbnormalClosure StatusCode = 1006

	// StatusNoStatusRcvd is a special code designated for use in applications.
	StatusNoStatusRcvd StatusCode = 1005
)

// In reports whether the code is defined in given range.
func (s StatusCode) In(r StatusCodeRange) bool {
	return r.Min <= s && s <= r.Max
}

// Empty reports whether the code is empty.
// Empty code has no any meaning neither app level codes nor other.
// This method is useful just to check that code is golang default value 0.
func (s StatusCode) Empty() bool {
	return s == 0
}

// IsNotUsed reports whether the code is predefined in not used range.
func (s StatusCode) IsNotUsed() bool {
	return s.In(StatusRangeNotInUse)
}

// IsApplicationSpec reports whether the code should be defined by
// application, framework or libraries specification.
func (s StatusCode) IsApplicationSpec() bool {
	return s.In(StatusRangeApplication)
}

// IsPrivateSpec reports whether the code should be defined privately.
func (s StatusCode) IsPrivateSpec() bool {
	return s.In(StatusRangePrivate)
}

// IsProtocolSpec reports whether the code should be defined by protocol specification.
func (s StatusCode) IsProtocolSpec() bool {
	return s.In(StatusRangeProtocol)
}

// IsProtocolDefined reports whether the code is already defined by protocol specification.
func (s StatusCode) IsProtocolDefined() bool {
	switch s {
	case StatusNormalClosure,
		StatusGoingAway,
		StatusProtocolError,
		StatusUnsupportedData,
		StatusInvalidFramePayloadData,
		StatusPolicyViolation,
		StatusMessageTooBig,
		StatusMandatoryExt,
		StatusInternalServerError,
		StatusNoStatusRcvd,
		StatusAbnormalClosure,
		StatusTLSHandshake:
		return true
	}
	return false
}

// IsProtocolReserved reports whether the code is defined by protocol specification
// to be reserved only for application usage purpose.
func (s StatusCode) IsProtocolReserved() bool {
	switch s {
	// [RFC6455]: {1005,1006,1015} is a reserved value and MUST NOT be set as a status code in a
	// Close control frame by an endpoint.
	case StatusNoStatusRcvd, StatusAbnormalClosure, StatusTLSHandshake:
		return true
	default:
		return false
	}
}

// Compiled control frames for common use cases.
// For construct-serialize optimizations.
var (
	CompiledPing  = MustCompileFrame(NewPingFrame(nil))
	CompiledPong  = MustCompileFrame(NewPongFrame(nil))
	CompiledClose = MustCompileFrame(NewCloseFrame(nil))

	CompiledCloseNormalClosure           = MustCompileFrame(closeFrameNormalClosure)
	CompiledCloseGoingAway               = MustCompileFrame(closeFrameGoingAway)
	CompiledCloseProtocolError           = MustCompileFrame(closeFrameProtocolError)
	CompiledCloseUnsupportedData         = MustCompileFrame(closeFrameUnsupportedData)
	CompiledCloseNoMeaningYet            = MustCompileFrame(closeFrameNoMeaningYet)
	CompiledCloseInvalidFramePayloadData = MustCompileFrame(closeFrameInvalidFramePayloadData)
	CompiledClosePolicyViolation         = MustCompileFrame(closeFramePolicyViolation)
	CompiledCloseMessageTooBig           = MustCompileFrame(closeFrameMessageTooBig)
	CompiledCloseMandatoryExt            = MustCompileFrame(closeFrameMandatoryExt)
	CompiledCloseInternalServerError     = MustCompileFrame(closeFrameInternalServerError)
	CompiledCloseTLSHandshake            = MustCompileFrame(closeFrameTLSHandshake)
)

// Header represents websocket frame header.
// See https://tools.ietf.org/html/rfc6455#section-5.2
type Header struct {
	Fin    bool
	Rsv    byte
	OpCode OpCode
	Masked bool
	Mask   [4]byte
	Length int64
}

// Rsv1 reports whether the header has first rsv bit set.
func (h Header) Rsv1() bool { return h.Rsv&bit5 != 0 }

// Rsv2 reports whether the header has second rsv bit set.
func (h Header) Rsv2() bool { return h.Rsv&bit6 != 0 }

// Rsv3 reports whether the header has third rsv bit set.
func (h Header) Rsv3() bool { return h.Rsv&bit7 != 0 }

// Frame represents websocket frame.
// See https://tools.ietf.org/html/rfc6455#section-5.2
type Frame struct {
	Header  Header
	Payload []byte
}

// NewFrame creates frame with given operation code,
// flag of completeness and payload bytes.
func NewFrame(op OpCode, fin bool, p []byte) Frame {
	return Frame{
		Header: Header{
			Fin:    fin,
			OpCode: op,
			Length: int64(len(p)),
		},
		Payload: p,
	}
}

// NewTextFrame creates text frame with p as payload.
// Note that p is not copied.
func NewTextFrame(p []byte) Frame {
	return NewFrame(OpText, true, p)
}

// NewBinaryFrame creates binary frame with p as payload.
// Note that p is not copied.
func NewBinaryFrame(p []byte) Frame {
	return NewFrame(OpBinary, true, p)
}

// NewPingFrame creates ping frame with p as payload.
// Note that p is not copied.
// Note that p must have length of MaxControlFramePayloadSize bytes or less due
// to RFC.
func NewPingFrame(p []byte) Frame {
	return NewFrame(OpPing, true, p)
}

// NewPongFrame creates pong frame with p as payload.
// Note that p is not copied.
// Note that p must have length of MaxControlFramePayloadSize bytes or less due
// to RFC.
func NewPongFrame(p []byte) Frame {
	return NewFrame(OpPong, true, p)
}

// NewCloseFrame creates close frame with given close body.
// Note that p is not copied.
// Note that p must have length of MaxControlFramePayloadSize bytes or less due
// to RFC.
func NewCloseFrame(p []byte) Frame {
	return NewFrame(OpClose, true, p)
}

// NewCloseFrameBody encodes a closure code and a reason into a binary
// representation.
//
// It returns slice which is at most MaxControlFramePayloadSize bytes length.
// If the reason is too big it will be cropped to fit the limit defined by the
// spec.
//
// See https://tools.ietf.org/html/rfc6455#section-5.5
func NewCloseFrameBody(code StatusCode, reason string) []byte {
	n := min(2+len(reason), MaxControlFramePayloadSize)
	p := make([]byte, n)

	crop := min(MaxControlFramePayloadSize-2, len(reason))
	PutCloseFrameBody(p, code, reason[:crop])

	return p
}

// PutCloseFrameBody encodes code and reason into buf.
//
// It will panic if the buffer is too small to accommodate a code or a reason.
//
// PutCloseFrameBody does not check buffer to be RFC compliant, but note that
// by RFC it must be at most MaxControlFramePayloadSize.
func PutCloseFrameBody(p []byte, code StatusCode, reason string) {
	_ = p[1+len(reason)]
	binary.BigEndian.PutUint16(p, uint16(code))
	copy(p[2:], reason)
}

// MaskFrame masks frame and returns frame with masked payload and Mask header's field set.
// Note that it copies f payload to prevent collisions.
// For less allocations you could use MaskFrameInPlace or construct frame manually.
func MaskFrame(f Frame) Frame {
	return MaskFrameWith(f, NewMask())
}

// MaskFrameWith masks frame with given mask and returns frame
// with masked payload and Mask header's field set.
// Note that it copies f payload to prevent collisions.
// For less allocations you could use MaskFrameInPlaceWith or construct frame manually.
func MaskFrameWith(f Frame, mask [4]byte) Frame {
	// TODO(gobwas): check CopyCipher ws copy() Cipher().
	p := make([]byte, len(f.Payload))
	copy(p, f.Payload)
	f.Payload = p
	return MaskFrameInPlaceWith(f, mask)
}

// MaskFrameInPlace masks frame and returns frame with masked payload and Mask
// header's field set.
// Note that it applies xor cipher to f.Payload without copying, that is, it
// modifies f.Payload inplace.
func MaskFrameInPlace(f Frame) Frame {
	return MaskFrameInPlaceWith(f, NewMask())
}

// MaskFrameInPlaceWith masks frame with given mask and returns frame
// with masked payload and Mask header's field set.
// Note that it applies xor cipher to f.Payload without copying, that is, it
// modifies f.Payload inplace.
func MaskFrameInPlaceWith(f Frame, m [4]byte) Frame {
	f.Header.Masked = true
	f.Header.Mask = m
	Cipher(f.Payload, m, 0)
	return f
}

// NewMask creates new random mask.
func NewMask() (ret [4]byte) {
	binary.BigEndian.PutUint32(ret[:], rand.Uint32())
	return
}

// CompileFrame returns byte representation of given frame.
// In terms of memory consumption it is useful to precompile static frames
// which are often used.
func CompileFrame(f Frame) (bts []byte, err error) {
	buf := bytes.NewBuffer(make([]byte, 0, 16))
	err = WriteFrame(buf, f)
	bts = buf.Bytes()
	return
}

// MustCompileFrame is like CompileFrame but panics if frame can not be
// encoded.
func MustCompileFrame(f Frame) []byte {
	bts, err := CompileFrame(f)
	if err != nil {
		panic(err)
	}
	return bts
}

// Rsv creates rsv byte representation.
func Rsv(r1, r2, r3 bool) (rsv byte) {
	if r1 {
		rsv |= bit5
	}
	if r2 {
		rsv |= bit6
	}
	if r3 {
		rsv |= bit7
	}
	return rsv
}

func makeCloseFrame(code StatusCode, reason string) Frame {
	return NewCloseFrame(NewCloseFrameBody(
		code, reason,
	))
}

var (
	closeFrameNormalClosure           = makeCloseFrame(StatusNormalClosure, "")
	closeFrameGoingAway               = makeCloseFrame(StatusGoingAway, "")
	closeFrameProtocolError           = makeCloseFrame(StatusProtocolError, "")
	closeFrameUnsupportedData         = makeCloseFrame(StatusUnsupportedData, "")
	closeFrameNoMeaningYet            = makeCloseFrame(StatusNoMeaningYet, "")
	closeFrameInvalidFramePayloadData = makeCloseFrame(StatusInvalidFramePayloadData, "")
	closeFramePolicyViolation         = makeCloseFrame(StatusPolicyViolation, "")
	closeFrameMessageTooBig           = makeCloseFrame(StatusMessageTooBig, "")
	closeFrameMandatoryExt            = makeCloseFrame(StatusMandatoryExt, "")
	closeFrameInternalServerError     = makeCloseFrame(StatusInternalServerError, "")
	closeFrameTLSHandshake            = makeCloseFrame(StatusTLSHandshake, "")
)
<|endoftext|>