<commit_before>package rest

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"sync"
)

// JSON является вспомогательным типом для быстрого создания JSON-структур.
type JSON map[string]interface{}

// CompressData разрешает поддержку сжатия данных, если это поддерживается браузером.
// Если сжатие данных уже поддерживается, например, на уровне вашего обработчика, то вы можете
// заблокировать двойное сжатие, установив значение false.
var CompressData = true

// Context содержит контекстную информацию HTTP-запроса и методы удобного формирования ответа
// на них.
type Context struct {
	// HTTP запрос в разобранном виде
	*http.Request
	// именованные параметры из пути запроса
	Params []Param
	// интерфейс для публикации ответа на запрос
	Response http.ResponseWriter
	// тип информации в ответе
	ContentType string
	// код HTTP-ответа
	status int
	// разобранные параметры запроса в URL (кеш)
	urlQuery url.Values
	// дополнительные данные, устанавливаемые пользователем
	// в качестве ключа рекомендуется использовать приватный тип
	// и какое-нибудь его значение, что позволит застраховаться от
	// случайной перезаписи этих данных
	data map[interface{}]interface{}
}

// newContext возвращает новый инициализированный контекст. В отличии от просто создания нового
// контекста, вызов данного метода использует пул контекстов.
func newContext(w http.ResponseWriter, r *http.Request, params []Param) *Context {
	context := contexts.Get().(*Context)
	context.Request = r
	context.Params = params
	context.urlQuery = nil
	context.data = nil
	context.Response = w
	context.ContentType = ""
	context.status = 0
	return context
}

// free возвращает контекст в пул используемых контекстов для дальнейшего использования.
// Вызывается автоматически после того, как контекст перестает использоваться.
func (c *Context) free() {
	contexts.Put(c)
}

// Get возвращает значение именованного параметра. Если параметр с таким именем не найден,
// то возвращается значение параметра из URL с тем же именем. Разбор параметров запроса сохраняется
// внутри Context и повторного его разбора уже не требует. Но это происходит только при первом
// к ним обращении.
func (c *Context) Get(key string) string {
	for _, param := range c.Params {
		if param.Key == key {
			return param.Value
		}
	}
	if c.urlQuery == nil {
		c.urlQuery = c.Request.URL.Query()
	}
	return c.urlQuery.Get(key)
}

// Data возвращает пользовательские данные, сохраненные в контексте запроса с указанным ключем.
func (c *Context) Data(key interface{}) interface{} {
	if c.data == nil {
		return nil
	}
	return c.data[key]
}

// DataSet сохраняет пользовательские данные в контексте запроса с указанным ключем.
// Рекомендуется в качестве ключа использовать какой-нибудь приватный тип и его значение,
// чтобы избежать случайного затирания данных другими обработчиками. Это гарантированно обезопасит
// их от случайного доступа к ним.
func (c *Context) DataSet(key, value interface{}) {
	if c.data == nil {
		c.data = make(map[interface{}]interface{})
	}
	c.data[key] = value
}

// Code устанавливает код HTTP-ответа, который будет отправлен сервером. Данный метод возвращает
// ссылку на основной контекст, чтобы можно было использовать его в последовательности выполнения
// команд. Например, можно сразу установить код ответа и тут же опубликовать данные.
func (c *Context) Code(code int) *Context {
	if code >= 200 && code < 600 {
		c.status = code
	}
	return c
}

// SetHeader устанавливает новое значение для указанного HTTP-заголовка. Если передаваемое
// значение заголовка пустое, то данный заголовок будет удален.
func (c *Context) SetHeader(key, value string) {
	if value == "" {
		c.Response.Header().Del(key)
	} else {
		c.Response.Header().Set(key, value)
	}
}

// Parse декодирует содержимое запроса в объект. После чтения из запроса
// http.Request.Body автоматически закрывается и дополнительного закрытия не требуется.
//
// На данный момент поддерживается только разбор объектов в формате JSON.
func (c *Context) Parse(obj interface{}) error {
	defer c.Request.Body.Close()
	return json.NewDecoder(c.Request.Body).Decode(obj)
}

// Body публикует данные, переданные в параметре, в качестве ответа. Если ContentType не указан,
// то используется "application/json".
//
// В зависимости от типа передаваемых данных, ответ формируется по разному.
// Если данные являются бинарными ([]byte) или поддерживают интерфейс io.Reader, то данные отдаются
// как есть, без какого-либо изменения. Если io.Reader поддерживает io.Close, то он будет
// автоматически закрыт. Строки и ошибки преобразуются в простое JSON-сообщение, состоящие из кода
// статуса и текста сообщения. Остальные типы приводятся к формату JSON.
//
// Если клиент поддерживает сжатие при передаче данных, то автоматически включается поддержка
// сжатия ответа. Чтобы отключить данное поведение, необходимо установить флаг CompressData в false.
func (c *Context) Body(data interface{}) {
	var headers = c.Response.Header() // быстрый доступ к заголовкам ответа
	if c.ContentType == "" {
		c.ContentType = "application/json; charset=utf-8"
	}
	headers.Set("Content-Type", c.ContentType)
	// поддерживаем компрессию, если она поддерживается клиентом и не запрещена в библиотеке
	var writer io.Writer = c.Response
	if CompressData {
		switch accept := c.Request.Header.Get("Accept-Encoding"); {
		case strings.Contains(accept, "gzip"): // Поддерживается gzip-сжатие
			headers.Set("Content-Encoding", "gzip")
			headers.Add("Vary", "Accept-Encoding")
			writer = gzipGet(writer)
			defer gzipPut(writer.(io.Closer))
		case strings.Contains(accept, "deflate"): // Поддерживается deflate-сжатие
			headers.Set("Content-Encoding", "deflate")
			headers.Add("Vary", "Accept-Encoding")
			writer = deflateGet(writer)
			defer deflatePut(writer.(io.Closer))
		}
	}
	// обрабатываем статус выполнения запроса
	if c.status == 0 {
		c.status = http.StatusOK
	}
	c.Response.WriteHeader(c.status) // отдаем статус ответа
	enc := json.NewEncoder(writer)   // инициализируем JSON-encoder
	// в зависимости от типа данных поддерживаются разные методы вывода
	var err error
	switch data := data.(type) {
	case nil: // нечего отдавать
		if c.status >= 400 { // если статус соответствует ошибке, то формируем текст с ее описанием
			err = enc.Encode(JSON{"code": c.status, "error": http.StatusText(c.status)})
		}
	case io.Reader: // поток данных отдаем как есть
		_, err = io.Copy(writer, data)
		if data, ok := data.(io.Closer); ok {
			data.Close() // закрываем по окончании, раз поддерживается
		}
	case []byte: // уже готовый к отдаче набор данных
		_, err = writer.Write(data) // тоже отдаем как есть
	case error: // ошибки возвращаем в виде специального JSON
		err = enc.Encode(JSON{"code": c.status, "error": data.Error()})
	case string: // строки тоже возвращаем в виде специального JSON
		m := JSON{"code": c.status}
		if c.status >= 400 { // в случае ошибок это будет error
			m["error"] = data
		} else { // с случае просто текстовых сообщений — message
			m["message"] = data
		}
		err = enc.Encode(m)
	default: // во всех остальных случаях отдаем JSON-представление
		err = enc.Encode(data)
	}
	// если возникла ошибка, то пытаемся ее вернуть
	if err != nil {
		// почти http.Error
		headers.Set("Content-Type", "text/plain; charset=utf-8")
		headers.Set("X-Content-Type-Options", "nosniff")
		c.Response.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintln(writer, err)
	}
}

// contexts содержит пул контекстов
var contexts = sync.Pool{New: func() interface{} { return new(Context) }}
<commit_msg>compress<commit_after>package rest

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"sync"
)

// JSON является вспомогательным типом для быстрого создания JSON-структур.
type JSON map[string]interface{}

// Compress разрешает поддержку сжатия данных, если это поддерживается браузером.
// Если сжатие данных уже поддерживается, например, на уровне вашего обработчика, то вы можете
// заблокировать двойное сжатие, установив значение false.
var Compress = true

// Context содержит контекстную информацию HTTP-запроса и методы удобного формирования ответа
// на них.
type Context struct {
	// HTTP запрос в разобранном виде
	*http.Request
	// именованные параметры из пути запроса
	Params []Param
	// интерфейс для публикации ответа на запрос
	Response http.ResponseWriter
	// тип информации в ответе
	ContentType string
	// код HTTP-ответа
	status int
	// разобранные параметры запроса в URL (кеш)
	urlQuery url.Values
	// дополнительные данные, устанавливаемые пользователем
	// в качестве ключа рекомендуется использовать приватный тип
	// и какое-нибудь его значение, что позволит застраховаться от
	// случайной перезаписи этих данных
	data map[interface{}]interface{}
}

// newContext возвращает новый инициализированный контекст. В отличии от просто создания нового
// контекста, вызов данного метода использует пул контекстов.
func newContext(w http.ResponseWriter, r *http.Request, params []Param) *Context {
	context := contexts.Get().(*Context)
	context.Request = r
	context.Params = params
	context.urlQuery = nil
	context.data = nil
	context.Response = w
	context.ContentType = ""
	context.status = 0
	return context
}

// free возвращает контекст в пул используемых контекстов для дальнейшего использования.
// Вызывается автоматически после того, как контекст перестает использоваться.
func (c *Context) free() {
	contexts.Put(c)
}

// Get возвращает значение именованного параметра. Если параметр с таким именем не найден,
// то возвращается значение параметра из URL с тем же именем. Разбор параметров запроса сохраняется
// внутри Context и повторного его разбора уже не требует. Но это происходит только при первом
// к ним обращении.
func (c *Context) Get(key string) string {
	for _, param := range c.Params {
		if param.Key == key {
			return param.Value
		}
	}
	if c.urlQuery == nil {
		c.urlQuery = c.Request.URL.Query()
	}
	return c.urlQuery.Get(key)
}

// Data возвращает пользовательские данные, сохраненные в контексте запроса с указанным ключем.
func (c *Context) Data(key interface{}) interface{} {
	if c.data == nil {
		return nil
	}
	return c.data[key]
}

// DataSet сохраняет пользовательские данные в контексте запроса с указанным ключем.
// Рекомендуется в качестве ключа использовать какой-нибудь приватный тип и его значение,
// чтобы избежать случайного затирания данных другими обработчиками. Это гарантированно обезопасит
// их от случайного доступа к ним.
func (c *Context) DataSet(key, value interface{}) {
	if c.data == nil {
		c.data = make(map[interface{}]interface{})
	}
	c.data[key] = value
}

// Code устанавливает код HTTP-ответа, который будет отправлен сервером. Данный метод возвращает
// ссылку на основной контекст, чтобы можно было использовать его в последовательности выполнения
// команд. Например, можно сразу установить код ответа и тут же опубликовать данные.
func (c *Context) Code(code int) *Context {
	if code >= 200 && code < 600 {
		c.status = code
	}
	return c
}

// SetHeader устанавливает новое значение для указанного HTTP-заголовка. Если передаваемое
// значение заголовка пустое, то данный заголовок будет удален.
func (c *Context) SetHeader(key, value string) {
	if value == "" {
		c.Response.Header().Del(key)
	} else {
		c.Response.Header().Set(key, value)
	}
}

// Parse декодирует содержимое запроса в объект. После чтения из запроса
// http.Request.Body автоматически закрывается и дополнительного закрытия не требуется.
//
// На данный момент поддерживается только разбор объектов в формате JSON.
func (c *Context) Parse(obj interface{}) error {
	defer c.Request.Body.Close()
	return json.NewDecoder(c.Request.Body).Decode(obj)
}

// Body публикует данные, переданные в параметре, в качестве ответа. Если ContentType не указан,
// то используется "application/json".
//
// В зависимости от типа передаваемых данных, ответ формируется по разному.
// Если данные являются бинарными ([]byte) или поддерживают интерфейс io.Reader, то данные отдаются
// как есть, без какого-либо изменения. Если io.Reader поддерживает io.Close, то он будет
// автоматически закрыт. Строки и ошибки преобразуются в простое JSON-сообщение, состоящие из кода
// статуса и текста сообщения. Остальные типы приводятся к формату JSON.
//
// Если клиент поддерживает сжатие при передаче данных, то автоматически включается поддержка
// сжатия ответа. Чтобы отключить данное поведение, необходимо установить флаг Compress в false.
func (c *Context) Body(data interface{}) {
	var headers = c.Response.Header() // быстрый доступ к заголовкам ответа
	if c.ContentType == "" {
		c.ContentType = "application/json; charset=utf-8"
	}
	headers.Set("Content-Type", c.ContentType)
	// поддерживаем компрессию, если она поддерживается клиентом и не запрещена в библиотеке
	var writer io.Writer = c.Response
	if Compress {
		switch accept := c.Request.Header.Get("Accept-Encoding"); {
		case strings.Contains(accept, "gzip"): // Поддерживается gzip-сжатие
			headers.Set("Content-Encoding", "gzip")
			headers.Add("Vary", "Accept-Encoding")
			writer = gzipGet(writer)
			defer gzipPut(writer.(io.Closer))
		case strings.Contains(accept, "deflate"): // Поддерживается deflate-сжатие
			headers.Set("Content-Encoding", "deflate")
			headers.Add("Vary", "Accept-Encoding")
			writer = deflateGet(writer)
			defer deflatePut(writer.(io.Closer))
		}
	}
	// обрабатываем статус выполнения запроса
	if c.status == 0 {
		c.status = http.StatusOK
	}
	c.Response.WriteHeader(c.status) // отдаем статус ответа
	enc := json.NewEncoder(writer)   // инициализируем JSON-encoder
	// в зависимости от типа данных поддерживаются разные методы вывода
	var err error
	switch data := data.(type) {
	case nil: // нечего отдавать
		if c.status >= 400 { // если статус соответствует ошибке, то формируем текст с ее описанием
			err = enc.Encode(JSON{"code": c.status, "error": http.StatusText(c.status)})
		}
	case io.Reader: // поток данных отдаем как есть
		_, err = io.Copy(writer, data)
		if data, ok := data.(io.Closer); ok {
			data.Close() // закрываем по окончании, раз поддерживается
		}
	case []byte: // уже готовый к отдаче набор данных
		_, err = writer.Write(data) // тоже отдаем как есть
	case error: // ошибки возвращаем в виде специального JSON
		err = enc.Encode(JSON{"code": c.status, "error": data.Error()})
	case string: // строки тоже возвращаем в виде специального JSON
		m := JSON{"code": c.status}
		if c.status >= 400 { // в случае ошибок это будет error
			m["error"] = data
		} else { // с случае просто текстовых сообщений — message
			m["message"] = data
		}
		err = enc.Encode(m)
	default: // во всех остальных случаях отдаем JSON-представление
		err = enc.Encode(data)
	}
	// если возникла ошибка, то пытаемся ее вернуть
	if err != nil {
		// почти http.Error
		headers.Set("Content-Type", "text/plain; charset=utf-8")
		headers.Set("X-Content-Type-Options", "nosniff")
		c.Response.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintln(writer, err)
	}
}

// contexts содержит пул контекстов
var contexts = sync.Pool{New: func() interface{} { return new(Context) }}
<|endoftext|>


<commit_before>package cli

import (
	"flag"
	"strconv"
)

// Context is a type that is passed through to
// each Handler action in a cli application. Context
// can be used to retrieve context-specific Args and
// parsed command-line options.
type Context struct {
	App       *App
	flagSet   *flag.FlagSet
	globalSet *flag.FlagSet
}

// Creates a new context. For use in when invoking an App or Command action.
func NewContext(app *App, set *flag.FlagSet, globalSet *flag.FlagSet) *Context {
	return &Context{app, set, globalSet}
}

// Looks up the value of a local int flag, returns 0 if no int flag exists
func (c *Context) Int(name string) int {
	return c.lookupInt(name, c.flagSet)
}

// Looks up the value of a local bool flag, returns false if no bool flag exists
func (c *Context) Bool(name string) bool {
	return c.lookupBool(name, c.flagSet)
}

// Looks up the value of a local string flag, returns "" if no string flag exists
func (c *Context) String(name string) string {
	return c.lookupString(name, c.flagSet)
}

// Looks up the value of a local string slice flag, returns nil if no string slice flag exists
func (c *Context) StringSlice(name string) []string {
	return c.lookupStringSlice(name, c.flagSet)
}

// Looks up the value of a local int slice flag, returns nil if no int slice flag exists
func (c *Context) IntSlice(name string) []int {
	return c.lookupIntSlice(name, c.flagSet)
}

// Looks up the value of a global int flag, returns 0 if no int flag exists
func (c *Context) GlobalInt(name string) int {
	return c.lookupInt(name, c.globalSet)
}

// Looks up the value of a global bool flag, returns false if no bool flag exists
func (c *Context) GlobalBool(name string) bool {
	return c.lookupBool(name, c.globalSet)
}

// Looks up the value of a global string flag, returns "" if no string flag exists
func (c *Context) GlobalString(name string) string {
	return c.lookupString(name, c.globalSet)
}

// Looks up the value of a global string slice flag, returns nil if no string slice flag exists
func (c *Context) GlobalStringSlice(name string) []string {
	return c.lookupStringSlice(name, c.globalSet)
}

// Looks up the value of a global int slice flag, returns nil if no int slice flag exists
func (c *Context) GlobalIntSlice(name string) []int {
	return c.lookupIntSlice(name, c.globalSet)
}

// Returns the command line arguments associated with the context.
func (c *Context) Args() []string {
	return c.flagSet.Args()
}

func (c *Context) lookupInt(name string, set *flag.FlagSet) int {
	f := set.Lookup(name)
	if f != nil {
		val, err := strconv.Atoi(f.Value.String())
		if err != nil {
			return 0
		}
		return val
	}

	return 0
}

func (c *Context) lookupString(name string, set *flag.FlagSet) string {
	f := set.Lookup(name)
	if f != nil {
		return f.Value.String()
	}

	return ""
}

func (c *Context) lookupStringSlice(name string, set *flag.FlagSet) []string {
	f := set.Lookup(name)
	if f != nil {
		return (f.Value.(*StringSlice)).Value()

	}

	return nil
}

func (c *Context) lookupIntSlice(name string, set *flag.FlagSet) []int {
	f := set.Lookup(name)
	if f != nil {
		return (f.Value.(*IntSlice)).Value()

	}

	return nil
}

func (c *Context) lookupBool(name string, set *flag.FlagSet) bool {
	f := set.Lookup(name)
	if f != nil {
		val, err := strconv.ParseBool(f.Value.String())
		if err != nil {
			return false
		}
		return val
	}

	return false
}
<commit_msg>Added two convenience functions for retrieving arguments<commit_after>package cli

import (
	"flag"
	"strconv"
)

// Context is a type that is passed through to
// each Handler action in a cli application. Context
// can be used to retrieve context-specific Args and
// parsed command-line options.
type Context struct {
	App       *App
	flagSet   *flag.FlagSet
	globalSet *flag.FlagSet
}

// Creates a new context. For use in when invoking an App or Command action.
func NewContext(app *App, set *flag.FlagSet, globalSet *flag.FlagSet) *Context {
	return &Context{app, set, globalSet}
}

// Looks up the value of a local int flag, returns 0 if no int flag exists
func (c *Context) Int(name string) int {
	return c.lookupInt(name, c.flagSet)
}

// Looks up the value of a local bool flag, returns false if no bool flag exists
func (c *Context) Bool(name string) bool {
	return c.lookupBool(name, c.flagSet)
}

// Looks up the value of a local string flag, returns "" if no string flag exists
func (c *Context) String(name string) string {
	return c.lookupString(name, c.flagSet)
}

// Looks up the value of a local string slice flag, returns nil if no string slice flag exists
func (c *Context) StringSlice(name string) []string {
	return c.lookupStringSlice(name, c.flagSet)
}

// Looks up the value of a local int slice flag, returns nil if no int slice flag exists
func (c *Context) IntSlice(name string) []int {
	return c.lookupIntSlice(name, c.flagSet)
}

// Looks up the value of a global int flag, returns 0 if no int flag exists
func (c *Context) GlobalInt(name string) int {
	return c.lookupInt(name, c.globalSet)
}

// Looks up the value of a global bool flag, returns false if no bool flag exists
func (c *Context) GlobalBool(name string) bool {
	return c.lookupBool(name, c.globalSet)
}

// Looks up the value of a global string flag, returns "" if no string flag exists
func (c *Context) GlobalString(name string) string {
	return c.lookupString(name, c.globalSet)
}

// Looks up the value of a global string slice flag, returns nil if no string slice flag exists
func (c *Context) GlobalStringSlice(name string) []string {
	return c.lookupStringSlice(name, c.globalSet)
}

// Looks up the value of a global int slice flag, returns nil if no int slice flag exists
func (c *Context) GlobalIntSlice(name string) []int {
	return c.lookupIntSlice(name, c.globalSet)
}

// Returns the command line arguments associated with the context.
func (c *Context) Args() []string {
	return c.flagSet.Args()
}

func (c *Context) lookupInt(name string, set *flag.FlagSet) int {
	f := set.Lookup(name)
	if f != nil {
		val, err := strconv.Atoi(f.Value.String())
		if err != nil {
			return 0
		}
		return val
	}

	return 0
}

func (c *Context) lookupString(name string, set *flag.FlagSet) string {
	f := set.Lookup(name)
	if f != nil {
		return f.Value.String()
	}

	return ""
}

func (c *Context) lookupStringSlice(name string, set *flag.FlagSet) []string {
	f := set.Lookup(name)
	if f != nil {
		return (f.Value.(*StringSlice)).Value()

	}

	return nil
}

func (c *Context) lookupIntSlice(name string, set *flag.FlagSet) []int {
	f := set.Lookup(name)
	if f != nil {
		return (f.Value.(*IntSlice)).Value()

	}

	return nil
}

func (c *Context) lookupBool(name string, set *flag.FlagSet) bool {
	f := set.Lookup(name)
	if f != nil {
		val, err := strconv.ParseBool(f.Value.String())
		if err != nil {
			return false
		}
		return val
	}

	return false
}

// Returns the nth argument, or just a blank string
func (c *Context) GetArg(n int) string {
	args := c.Args()
	if len(args) < n {
		return args[n]
	}
	return ""
}

// Returns the first argument, or just a blank string, for convenience
func (c *Context) FirstArg() string {
	return c.GetArg(0)
}
<|endoftext|>


<commit_before>package convert

import(
	"fmt"
	"strconv"
	"errors"
	"unsafe"
	"reflect"
)

// Convert integers to string, return empty string if the conversion fails
func Int2Str(val interface{}) string{
	switch val.(type){
		// Integers
		case int:
			return fmt.Sprintf("%d", val)
		case int8:
			return fmt.Sprintf("%d", val)
		case int16:
			return fmt.Sprintf("%d", val)
		case int32:
			return fmt.Sprintf("%d", val)
		case int64:
			return fmt.Sprintf("%d", val)
		case uint:
			return fmt.Sprintf("%d", val)
		case uint8:
			return fmt.Sprintf("%d", val)
		case uint16:
			return fmt.Sprintf("%d", val)
		case uint32:
			return fmt.Sprintf("%d", val)
		case uint64:
			return fmt.Sprintf("%d", val)
		// Type is not integers, return empty string
		default:
			return ""
	}

}

// Convert floats to string, parameter length specifies the number of digits behind the float point, return empty string if the conversion fails
func Float2Str(val interface{}, length int) string {
	switch val.(type){
		// Floats
		case float32:
			return fmt.Sprintf("%." + Int2Str(length) + "f", val)
		case float64:
			return fmt.Sprintf("%." + Int2Str(length) + "f", val)
			// Type is not floats, return empty string
		default:
			return ""
	}
}

// Convert bool to string
func Bool2Str(val bool) string {
	if val {
		return "true"
	}
	return "false"
}

func internalStr2Int(val string, bitSize int, noPanic bool) (int64, error) {
	res, err := strconv.ParseInt(val, 0, bitSize)
	if err != nil{
		if noPanic {
			return 0, err
		}else {
			panic(err)
		}
	}
	return res, nil
}

// Simply return the conversion result.
// For conversions that may panic, the code won't come here.
// For conversions that won't panic, res will be zero value and err will come here as well.
func wrapInt64Result(res int64, err error) int64 {
	return res
}

// Convert string to int64, panic when the string is not of a valid int64 format.
func Str2Int64(val string) int64 {
	return int64(wrapInt64Result(internalStr2Int(val, 64, false)))
}

// Convert string to int64, return 0 if the conversion fails
func Str2Int64NoPanic(val string) int64 {
	return int64(wrapInt64Result(internalStr2Int(val, 64, true)))
}

// Convert string to int64, return the default value you set when the conversion fails
func Str2Int64WithDefaultValue(val string, defaultVal int64) int64 {
	if res, err := internalStr2Int(val, 64, false); err != nil {
		return defaultVal
	} else {
		return int64(res)
	}
}

// Convert string to int32, panic when the string is not of a valid int32 format.
func Str2Int32(val string) int32 {
	return int32(wrapInt64Result(internalStr2Int(val, 32, false)))
}

// Convert string to int32, return 0 if the conversion fails
func Str2Int32NoPanic(val string) int32 {
	return int32(wrapInt64Result(internalStr2Int(val, 32, true)))
}

// Convert string to int32, return the default value you set when the conversion fails
func Str2Int32WithDefaultValue(val string, defaultVal int32) int32 {
	if res, err := internalStr2Int(val, 32, false); err != nil {
		return defaultVal
	} else {
		return int32(res)
	}
}

// Convert string to int16, panic when the string is not of a valid int16 format.
func Str2Int16(val string) int16 {
	return int16(wrapInt64Result(internalStr2Int(val, 16, false)))
}

// Convert string to int16, return 0 if the conversion fails
func Str2Int16NoPanic(val string) int16 {
	return int16(wrapInt64Result(internalStr2Int(val, 16, true)))
}

// Convert string to int16, return the default value you set when the conversion fails
func Str2Int16WithDefaultValue(val string, defaultVal int16) int16 {
	if res, err := internalStr2Int(val, 16, false); err != nil {
		return defaultVal
	} else {
		return int16(res)
	}
}

// Convert string to int8, panic when the string is not of a valid int8 format.
func Str2Int8(val string) int8 {
	return int8(wrapInt64Result(internalStr2Int(val, 8, false)))
}

// Convert string to int8, return 0 if the conversion fails
func Str2Int8NoPanic(val string) int8 {
	return int8(wrapInt64Result(internalStr2Int(val, 8, true)))
}

// Convert string to int8, return the default value you set when the conversion fails
func Str2Int8WithDefaultValue(val string, defaultVal int8) int8 {
	if res, err := internalStr2Int(val, 8, false); err != nil {
		return defaultVal
	} else {
		return int8(res)
	}
}

// Convert string to int, panic when the string is not of a valid int format.
func Str2Int(val string) int {
	return int(wrapInt64Result(internalStr2Int(val, 0, false)))
}

// Convert string to int, return 0 if the conversion fails
func Str2IntNoPanic(val string) int {
	return int(wrapInt64Result(internalStr2Int(val, 0, true)))
}

// Convert string to int, return the default value you set when the conversion fails
func Str2IntWithDefaultValue(val string, defaultVal int) int {
	if res, err := internalStr2Int(val, 0, false); err != nil {
		return defaultVal
	} else {
		return int(res)
	}
}

func internalStr2Uint(val string, bitSize int, noPanic bool) (uint64, error) {
	res, err := strconv.ParseUint(val, 0, bitSize)
	if err != nil{
		if noPanic {
			return 0, err
		}else {
			panic(err)
		}
	}
	return res, nil
}

// Simply return the conversion result.
// For conversions that may panic, the code won't come here.
// For conversions that won't panic, res will be zero value and err will come here as well.
func wrapUint64Result(res uint64, err error) uint64 {
	return res
}

// Convert string to uint64, panic when the string is not of a valid uint64 format.
func Str2Uint64(val string) uint64 {
	return uint64(wrapUint64Result(internalStr2Uint(val, 64, false)))
}

// Convert string to uint64, return 0 if the conversion fails
func Str2Uint64NoPanic(val string) uint64 {
	return uint64(wrapUint64Result(internalStr2Uint(val, 64, true)))
}

// Convert string to uint64, return the default value you set when the conversion fails
func Str2Uint64WithDefaultValue(val string, defaultVal uint64) uint64 {
	if res, err := internalStr2Uint(val, 64, false); err != nil {
		return defaultVal
	} else {
		return uint64(res)
	}
}

// Convert string to uint32, panic when the string is not of a valid uint32 format.
func Str2Uint32(val string) uint32 {
	return uint32(wrapUint64Result(internalStr2Uint(val, 32, false)))
}

// Convert string to uint32, return 0 if the conversion fails
func Str2Uint32NoPanic(val string) uint32 {
	return uint32(wrapUint64Result(internalStr2Uint(val, 32, true)))
}

// Convert string to uint32, return the default value you set when the conversion fails
func Str2Uint32WithDefaultValue(val string, defaultVal uint32) uint32 {
	if res, err := internalStr2Uint(val, 32, false); err != nil {
		return defaultVal
	} else {
		return uint32(res)
	}
}

// Convert string to uint16, panic when the string is not of a valid uint16 format.
func Str2Uint16(val string) uint16 {
	return uint16(wrapUint64Result(internalStr2Uint(val, 16, false)))
}

// Convert string to uint16, return 0 if the conversion fails
func Str2Uint16NoPanic(val string) uint16 {
	return uint16(wrapUint64Result(internalStr2Uint(val, 16, true)))
}

// Convert string to uint16, return the default value you set when the conversion fails
func Str2Uint16WithDefaultValue(val string, defaultVal uint16) uint16 {
	if res, err := internalStr2Uint(val, 16, false); err != nil {
		return defaultVal
	} else {
		return uint16(res)
	}
}

// Convert string to uint8, panic when the string is not of a valid uint8 format.
func Str2Uint8(val string) uint8 {
	return uint8(wrapUint64Result(internalStr2Uint(val, 8, false)))
}

// Convert string to uint8, return 0 if the conversion fails
func Str2Uint8NoPanic(val string) uint8 {
	return uint8(wrapUint64Result(internalStr2Uint(val, 8, true)))
}

// Convert string to uint16, return the default value you set when the conversion fails
func Str2Uint8WithDefaultValue(val string, defaultVal uint8) uint8 {
	if res, err := internalStr2Uint(val, 8, false); err != nil {
		return defaultVal
	} else {
		return uint8(res)
	}
}

// Convert string to uint, panic when the string is not of a valid uint format.
func Str2Uint(val string) uint {
	return uint(wrapUint64Result(internalStr2Uint(val, 0, false)))
}

// Convert string to uint, return 0 if the conversion fails
func Str2UintNoPanic(val string) uint {
	return uint(wrapUint64Result(internalStr2Uint(val, 0, true)))
}

// Convert string to uint, return the default value you set when the conversion fails
func Str2UintWithDefaultValue(val string, defaultVal uint) uint {
	if res, err := internalStr2Uint(val, 0, false); err != nil {
		return defaultVal
	} else {
		return uint(res)
	}
}

func internalStr2Float(val string, bitSize int, noPanic bool) (float64, error) {
	res, err := strconv.ParseFloat(val, bitSize)
	if err != nil{
		if noPanic {
			return 0, err
		}else {
			panic(err)
		}
	}
	return res, nil
}

// Simply return the conversion result.
// For conversions that may panic, the code won't come here.
// For conversions that won't panic, res will be zero value and err will come here as well.
func wrapFloat64Result(res float64, err error) float64 {
	return res
}

// Convert string to float64, panic when the string is not of a valid float64 format.
func Str2Float64(val string) float64 {
	return float64(wrapFloat64Result(internalStr2Float(val, 64, false)))
}

// Convert string to float64, return 0 if the conversion fails
func Str2Float64NoPanic(val string) float64 {
	return float64(wrapFloat64Result(internalStr2Float(val, 64, true)))
}

// Convert string to float64, return the default value you set when the conversion fails
func Str2Float64WithDefaultValue(val string, defaultVal float64) float64 {
	if res, err := internalStr2Float(val, 64, false); err != nil {
		return defaultVal
	} else {
		return float64(res)
	}
}

// Convert string to float32, panic when the string is not of a valid float32 format.
func Str2Float32(val string) float32 {
	return float32(wrapFloat64Result(internalStr2Float(val, 32, false)))
}

// Convert string to float32, return 0 if the conversion fails
func Str2Float32NoPanic(val string) float32 {
	return float32(wrapFloat64Result(internalStr2Float(val, 32, true)))
}

// Convert string to float32, return the default value you set when the conversion fails
func Str2Float32WithDefaultValue(val string, defaultVal float32) float32 {
	if res, err := internalStr2Float(val, 32, false); err != nil {
		return defaultVal
	} else {
		return float32(res)
	}
}

// Convert string to bool, panic when the string is not of a valid bool format
func Str2Bool(val string) bool {
	if val == "true" || val == "True" || val == "TRUE" {
		return true
	}
	if val == "false" || val == "False" || val == "FALSE" {
		return false
	}
	panic(errors.New("could not resolve bool value:" + val))
}

// Convert bool to int, never panics
func Bool2Int(val bool) int {
	if val == true {
		return 1
	} else {
		return 0
	}
}

// Convert different types to byte slice using types and functions in unsafe and reflect package.
// It has higher performance, but notice that it may be not safe when garbage collection happens.
// Use it when you need to temporary convert a long string to a byte slice and won't keep it for long time.
func Str2ByteSliceNonCopy(val string) []byte {
	pSliceHeader := &reflect.SliceHeader{}
	strHeader := (*reflect.StringHeader)(unsafe.Pointer(&val))
	pSliceHeader.Data = strHeader.Data
	pSliceHeader.Len = strHeader.Len
	pSliceHeader.Cap = strHeader.Len
	return *(*[]byte)(unsafe.Pointer(pSliceHeader))
}

// Zero-copy convert from byte slice to a string
func BytesSlice2StrNonCopy(val []byte) string {
	return *(*string)(unsafe.Pointer(&val))
}
<commit_msg>fix with default value bug<commit_after>package convert

import(
	"fmt"
	"strconv"
	"errors"
	"unsafe"
	"reflect"
)

// Convert integers to string, return empty string if the conversion fails
func Int2Str(val interface{}) string{
	switch val.(type){
		// Integers
		case int:
			return fmt.Sprintf("%d", val)
		case int8:
			return fmt.Sprintf("%d", val)
		case int16:
			return fmt.Sprintf("%d", val)
		case int32:
			return fmt.Sprintf("%d", val)
		case int64:
			return fmt.Sprintf("%d", val)
		case uint:
			return fmt.Sprintf("%d", val)
		case uint8:
			return fmt.Sprintf("%d", val)
		case uint16:
			return fmt.Sprintf("%d", val)
		case uint32:
			return fmt.Sprintf("%d", val)
		case uint64:
			return fmt.Sprintf("%d", val)
		// Type is not integers, return empty string
		default:
			return ""
	}

}

// Convert floats to string, parameter length specifies the number of digits behind the float point, return empty string if the conversion fails
func Float2Str(val interface{}, length int) string {
	switch val.(type){
		// Floats
		case float32:
			return fmt.Sprintf("%." + Int2Str(length) + "f", val)
		case float64:
			return fmt.Sprintf("%." + Int2Str(length) + "f", val)
			// Type is not floats, return empty string
		default:
			return ""
	}
}

// Convert bool to string
func Bool2Str(val bool) string {
	if val {
		return "true"
	}
	return "false"
}

func internalStr2Int(val string, bitSize int, noPanic bool) (int64, error) {
	res, err := strconv.ParseInt(val, 0, bitSize)
	if err != nil{
		if noPanic {
			return 0, err
		}else {
			panic(err)
		}
	}
	return res, nil
}

// Simply return the conversion result.
// For conversions that may panic, the code won't come here.
// For conversions that won't panic, res will be zero value and err will come here as well.
func wrapInt64Result(res int64, err error) int64 {
	return res
}

// Convert string to int64, panic when the string is not of a valid int64 format.
func Str2Int64(val string) int64 {
	return int64(wrapInt64Result(internalStr2Int(val, 64, false)))
}

// Convert string to int64, return 0 if the conversion fails
func Str2Int64NoPanic(val string) int64 {
	return int64(wrapInt64Result(internalStr2Int(val, 64, true)))
}

// Convert string to int64, return the default value you set when the conversion fails
func Str2Int64WithDefaultValue(val string, defaultVal int64) int64 {
	if res, err := internalStr2Int(val, 64, true); err != nil {
		return defaultVal
	} else {
		return int64(res)
	}
}

// Convert string to int32, panic when the string is not of a valid int32 format.
func Str2Int32(val string) int32 {
	return int32(wrapInt64Result(internalStr2Int(val, 32, false)))
}

// Convert string to int32, return 0 if the conversion fails
func Str2Int32NoPanic(val string) int32 {
	return int32(wrapInt64Result(internalStr2Int(val, 32, true)))
}

// Convert string to int32, return the default value you set when the conversion fails
func Str2Int32WithDefaultValue(val string, defaultVal int32) int32 {
	if res, err := internalStr2Int(val, 32, true); err != nil {
		return defaultVal
	} else {
		return int32(res)
	}
}

// Convert string to int16, panic when the string is not of a valid int16 format.
func Str2Int16(val string) int16 {
	return int16(wrapInt64Result(internalStr2Int(val, 16, false)))
}

// Convert string to int16, return 0 if the conversion fails
func Str2Int16NoPanic(val string) int16 {
	return int16(wrapInt64Result(internalStr2Int(val, 16, true)))
}

// Convert string to int16, return the default value you set when the conversion fails
func Str2Int16WithDefaultValue(val string, defaultVal int16) int16 {
	if res, err := internalStr2Int(val, 16, true); err != nil {
		return defaultVal
	} else {
		return int16(res)
	}
}

// Convert string to int8, panic when the string is not of a valid int8 format.
func Str2Int8(val string) int8 {
	return int8(wrapInt64Result(internalStr2Int(val, 8, false)))
}

// Convert string to int8, return 0 if the conversion fails
func Str2Int8NoPanic(val string) int8 {
	return int8(wrapInt64Result(internalStr2Int(val, 8, true)))
}

// Convert string to int8, return the default value you set when the conversion fails
func Str2Int8WithDefaultValue(val string, defaultVal int8) int8 {
	if res, err := internalStr2Int(val, 8, true); err != nil {
		return defaultVal
	} else {
		return int8(res)
	}
}

// Convert string to int, panic when the string is not of a valid int format.
func Str2Int(val string) int {
	return int(wrapInt64Result(internalStr2Int(val, 0, false)))
}

// Convert string to int, return 0 if the conversion fails
func Str2IntNoPanic(val string) int {
	return int(wrapInt64Result(internalStr2Int(val, 0, true)))
}

// Convert string to int, return the default value you set when the conversion fails
func Str2IntWithDefaultValue(val string, defaultVal int) int {
	if res, err := internalStr2Int(val, 0, true); err != nil {
		return defaultVal
	} else {
		return int(res)
	}
}

func internalStr2Uint(val string, bitSize int, noPanic bool) (uint64, error) {
	res, err := strconv.ParseUint(val, 0, bitSize)
	if err != nil{
		if noPanic {
			return 0, err
		}else {
			panic(err)
		}
	}
	return res, nil
}

// Simply return the conversion result.
// For conversions that may panic, the code won't come here.
// For conversions that won't panic, res will be zero value and err will come here as well.
func wrapUint64Result(res uint64, err error) uint64 {
	return res
}

// Convert string to uint64, panic when the string is not of a valid uint64 format.
func Str2Uint64(val string) uint64 {
	return uint64(wrapUint64Result(internalStr2Uint(val, 64, false)))
}

// Convert string to uint64, return 0 if the conversion fails
func Str2Uint64NoPanic(val string) uint64 {
	return uint64(wrapUint64Result(internalStr2Uint(val, 64, true)))
}

// Convert string to uint64, return the default value you set when the conversion fails
func Str2Uint64WithDefaultValue(val string, defaultVal uint64) uint64 {
	if res, err := internalStr2Uint(val, 64, true); err != nil {
		return defaultVal
	} else {
		return uint64(res)
	}
}

// Convert string to uint32, panic when the string is not of a valid uint32 format.
func Str2Uint32(val string) uint32 {
	return uint32(wrapUint64Result(internalStr2Uint(val, 32, false)))
}

// Convert string to uint32, return 0 if the conversion fails
func Str2Uint32NoPanic(val string) uint32 {
	return uint32(wrapUint64Result(internalStr2Uint(val, 32, true)))
}

// Convert string to uint32, return the default value you set when the conversion fails
func Str2Uint32WithDefaultValue(val string, defaultVal uint32) uint32 {
	if res, err := internalStr2Uint(val, 32, true); err != nil {
		return defaultVal
	} else {
		return uint32(res)
	}
}

// Convert string to uint16, panic when the string is not of a valid uint16 format.
func Str2Uint16(val string) uint16 {
	return uint16(wrapUint64Result(internalStr2Uint(val, 16, false)))
}

// Convert string to uint16, return 0 if the conversion fails
func Str2Uint16NoPanic(val string) uint16 {
	return uint16(wrapUint64Result(internalStr2Uint(val, 16, true)))
}

// Convert string to uint16, return the default value you set when the conversion fails
func Str2Uint16WithDefaultValue(val string, defaultVal uint16) uint16 {
	if res, err := internalStr2Uint(val, 16, true); err != nil {
		return defaultVal
	} else {
		return uint16(res)
	}
}

// Convert string to uint8, panic when the string is not of a valid uint8 format.
func Str2Uint8(val string) uint8 {
	return uint8(wrapUint64Result(internalStr2Uint(val, 8, false)))
}

// Convert string to uint8, return 0 if the conversion fails
func Str2Uint8NoPanic(val string) uint8 {
	return uint8(wrapUint64Result(internalStr2Uint(val, 8, true)))
}

// Convert string to uint16, return the default value you set when the conversion fails
func Str2Uint8WithDefaultValue(val string, defaultVal uint8) uint8 {
	if res, err := internalStr2Uint(val, 8, true); err != nil {
		return defaultVal
	} else {
		return uint8(res)
	}
}

// Convert string to uint, panic when the string is not of a valid uint format.
func Str2Uint(val string) uint {
	return uint(wrapUint64Result(internalStr2Uint(val, 0, false)))
}

// Convert string to uint, return 0 if the conversion fails
func Str2UintNoPanic(val string) uint {
	return uint(wrapUint64Result(internalStr2Uint(val, 0, true)))
}

// Convert string to uint, return the default value you set when the conversion fails
func Str2UintWithDefaultValue(val string, defaultVal uint) uint {
	if res, err := internalStr2Uint(val, 0, true); err != nil {
		return defaultVal
	} else {
		return uint(res)
	}
}

func internalStr2Float(val string, bitSize int, noPanic bool) (float64, error) {
	res, err := strconv.ParseFloat(val, bitSize)
	if err != nil{
		if noPanic {
			return 0, err
		}else {
			panic(err)
		}
	}
	return res, nil
}

// Simply return the conversion result.
// For conversions that may panic, the code won't come here.
// For conversions that won't panic, res will be zero value and err will come here as well.
func wrapFloat64Result(res float64, err error) float64 {
	return res
}

// Convert string to float64, panic when the string is not of a valid float64 format.
func Str2Float64(val string) float64 {
	return float64(wrapFloat64Result(internalStr2Float(val, 64, false)))
}

// Convert string to float64, return 0 if the conversion fails
func Str2Float64NoPanic(val string) float64 {
	return float64(wrapFloat64Result(internalStr2Float(val, 64, true)))
}

// Convert string to float64, return the default value you set when the conversion fails
func Str2Float64WithDefaultValue(val string, defaultVal float64) float64 {
	if res, err := internalStr2Float(val, 64, true); err != nil {
		return defaultVal
	} else {
		return float64(res)
	}
}

// Convert string to float32, panic when the string is not of a valid float32 format.
func Str2Float32(val string) float32 {
	return float32(wrapFloat64Result(internalStr2Float(val, 32, false)))
}

// Convert string to float32, return 0 if the conversion fails
func Str2Float32NoPanic(val string) float32 {
	return float32(wrapFloat64Result(internalStr2Float(val, 32, true)))
}

// Convert string to float32, return the default value you set when the conversion fails
func Str2Float32WithDefaultValue(val string, defaultVal float32) float32 {
	if res, err := internalStr2Float(val, 32, true); err != nil {
		return defaultVal
	} else {
		return float32(res)
	}
}

// Convert string to bool, panic when the string is not of a valid bool format
func Str2Bool(val string) bool {
	if val == "true" || val == "True" || val == "TRUE" {
		return true
	}
	if val == "false" || val == "False" || val == "FALSE" {
		return false
	}
	panic(errors.New("could not resolve bool value:" + val))
}

// Convert bool to int, never panics
func Bool2Int(val bool) int {
	if val == true {
		return 1
	} else {
		return 0
	}
}

// Convert different types to byte slice using types and functions in unsafe and reflect package.
// It has higher performance, but notice that it may be not safe when garbage collection happens.
// Use it when you need to temporary convert a long string to a byte slice and won't keep it for long time.
func Str2ByteSliceNonCopy(val string) []byte {
	pSliceHeader := &reflect.SliceHeader{}
	strHeader := (*reflect.StringHeader)(unsafe.Pointer(&val))
	pSliceHeader.Data = strHeader.Data
	pSliceHeader.Len = strHeader.Len
	pSliceHeader.Cap = strHeader.Len
	return *(*[]byte)(unsafe.Pointer(pSliceHeader))
}

// Zero-copy convert from byte slice to a string
func BytesSlice2StrNonCopy(val []byte) string {
	return *(*string)(unsafe.Pointer(&val))
}
<|endoftext|>


<commit_before>// Copyright 2012 Jesse van den Kieboom. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package flags

import (
	"reflect"
	"strconv"
	"strings"
	"time"
)

func getBase(options reflect.StructTag, base int) (int, error) {
	sbase := options.Get("base")

	var err error
	var ivbase int64

	if sbase != "" {
		ivbase, err = strconv.ParseInt(sbase, 10, 32)
		base = int(ivbase)
	}

	return base, err
}

func convertToString(val reflect.Value, options reflect.StructTag) string {
	tp := val.Type()

	switch tp.Kind() {
	case reflect.String:
		return val.String()
	case reflect.Bool:
		if val.Bool() {
			return "true"
		} else {
			return "false"
		}
	case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64:
		base, _ := getBase(options, 10)
		return strconv.FormatInt(val.Int(), base)
	case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		base, _ := getBase(options, 10)
		return strconv.FormatUint(val.Uint(), base)
	case reflect.Float32, reflect.Float64:
		return strconv.FormatFloat(val.Float(), 'g', -1, tp.Bits())
	case reflect.Slice:
		ret := "["

		for i := 0; i < val.Len(); i++ {
			if i != 0 {
				ret += ", "
			}

			ret += convertToString(val.Index(i), options)
		}

		return ret + "]"
	case reflect.Map:
		ret := "{"

		for i, key := range val.MapKeys() {
			if i != 0 {
				ret += ", "
			}

			ret += convertToString(val.MapIndex(key), options)
		}

		return ret + "}"
	}

	return ""
}

func convert(val string, retval reflect.Value, options reflect.StructTag) error {
	tp := retval.Type()

	// Support for time.Duration
	if tp == reflect.TypeOf((*time.Duration)(nil)).Elem() {
		parsed, err := time.ParseDuration(val)

		if err != nil {
			return err
		}

		retval.SetInt(int64(parsed))
	}

	switch tp.Kind() {
	case reflect.String:
		retval.SetString(val)
	case reflect.Bool:
		if val == "" {
			retval.SetBool(true)
		} else {
			b, err := strconv.ParseBool(val)

			if err != nil {
				return err
			}

			retval.SetBool(b)
		}
	case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64:
		base, err := getBase(options, 10)

		if err != nil {
			return err
		}

		parsed, err := strconv.ParseInt(val, base, tp.Bits())

		if err != nil {
			return err
		}

		retval.SetInt(parsed)
	case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		base, err := getBase(options, 10)

		if err != nil {
			return err
		}

		parsed, err := strconv.ParseUint(val, base, tp.Bits())

		if err != nil {
			return err
		}

		retval.SetUint(parsed)
	case reflect.Float32, reflect.Float64:
		parsed, err := strconv.ParseFloat(val, tp.Bits())

		if err != nil {
			return err
		}

		retval.SetFloat(parsed)
	case reflect.Slice:
		elemtp := tp.Elem()
		elemval := reflect.New(elemtp)

		if err := convert(val, elemval, options); err != nil {
			return err
		}

		retval.Set(reflect.Append(retval, reflect.Indirect(elemval)))
	case reflect.Map:
		parts := strings.SplitN(val, ":", 2)

		key := parts[0]
		var value string

		if len(parts) == 2 {
			value = parts[1]
		}

		keytp := tp.Key()
		keyval := reflect.New(keytp)

		if err := convert(key, keyval, options); err != nil {
			return err
		}

		valuetp := tp.Elem()
		valueval := reflect.New(valuetp)

		if err := convert(value, valueval, options); err != nil {
			return err
		}

		if retval.IsNil() {
			retval.Set(reflect.MakeMap(tp))
		}

		retval.SetMapIndex(reflect.Indirect(keyval), reflect.Indirect(valueval))
	}

	return nil
}

func wrapText(s string, l int, prefix string) string {
	// Basic text wrapping of s at spaces to fit in l
	var ret string

	s = strings.TrimSpace(s)

	for len(s) > l {
		// Try to split on space
		suffix := ""

		pos := strings.LastIndex(s[:l], " ")

		if pos < 0 {
			pos = l - 1
			suffix = "-\n"
		}

		if len(ret) != 0 {
			ret += "\n" + prefix
		}

		ret += strings.TrimSpace(s[:pos]) + suffix
		s = strings.TrimSpace(s[pos:])
	}

	if len(s) > 0 {
		if len(ret) != 0 {
			ret += "\n" + prefix
		}

		return ret + s
	}

	return ret
}
<commit_msg>add return to time.Duration parsing to avoid further parse logic<commit_after>// Copyright 2012 Jesse van den Kieboom. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package flags

import (
	"reflect"
	"strconv"
	"strings"
	"time"
)

func getBase(options reflect.StructTag, base int) (int, error) {
	sbase := options.Get("base")

	var err error
	var ivbase int64

	if sbase != "" {
		ivbase, err = strconv.ParseInt(sbase, 10, 32)
		base = int(ivbase)
	}

	return base, err
}

func convertToString(val reflect.Value, options reflect.StructTag) string {
	tp := val.Type()

	switch tp.Kind() {
	case reflect.String:
		return val.String()
	case reflect.Bool:
		if val.Bool() {
			return "true"
		} else {
			return "false"
		}
	case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64:
		base, _ := getBase(options, 10)
		return strconv.FormatInt(val.Int(), base)
	case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		base, _ := getBase(options, 10)
		return strconv.FormatUint(val.Uint(), base)
	case reflect.Float32, reflect.Float64:
		return strconv.FormatFloat(val.Float(), 'g', -1, tp.Bits())
	case reflect.Slice:
		ret := "["

		for i := 0; i < val.Len(); i++ {
			if i != 0 {
				ret += ", "
			}

			ret += convertToString(val.Index(i), options)
		}

		return ret + "]"
	case reflect.Map:
		ret := "{"

		for i, key := range val.MapKeys() {
			if i != 0 {
				ret += ", "
			}

			ret += convertToString(val.MapIndex(key), options)
		}

		return ret + "}"
	}

	return ""
}

func convert(val string, retval reflect.Value, options reflect.StructTag) error {
	tp := retval.Type()

	// Support for time.Duration
	if tp == reflect.TypeOf((*time.Duration)(nil)).Elem() {
		parsed, err := time.ParseDuration(val)

		if err != nil {
			return err
		}

		retval.SetInt(int64(parsed))
		return nil
	}

	switch tp.Kind() {
	case reflect.String:
		retval.SetString(val)
	case reflect.Bool:
		if val == "" {
			retval.SetBool(true)
		} else {
			b, err := strconv.ParseBool(val)

			if err != nil {
				return err
			}

			retval.SetBool(b)
		}
	case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64:
		base, err := getBase(options, 10)

		if err != nil {
			return err
		}

		parsed, err := strconv.ParseInt(val, base, tp.Bits())

		if err != nil {
			return err
		}

		retval.SetInt(parsed)
	case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		base, err := getBase(options, 10)

		if err != nil {
			return err
		}

		parsed, err := strconv.ParseUint(val, base, tp.Bits())

		if err != nil {
			return err
		}

		retval.SetUint(parsed)
	case reflect.Float32, reflect.Float64:
		parsed, err := strconv.ParseFloat(val, tp.Bits())

		if err != nil {
			return err
		}

		retval.SetFloat(parsed)
	case reflect.Slice:
		elemtp := tp.Elem()
		elemval := reflect.New(elemtp)

		if err := convert(val, elemval, options); err != nil {
			return err
		}

		retval.Set(reflect.Append(retval, reflect.Indirect(elemval)))
	case reflect.Map:
		parts := strings.SplitN(val, ":", 2)

		key := parts[0]
		var value string

		if len(parts) == 2 {
			value = parts[1]
		}

		keytp := tp.Key()
		keyval := reflect.New(keytp)

		if err := convert(key, keyval, options); err != nil {
			return err
		}

		valuetp := tp.Elem()
		valueval := reflect.New(valuetp)

		if err := convert(value, valueval, options); err != nil {
			return err
		}

		if retval.IsNil() {
			retval.Set(reflect.MakeMap(tp))
		}

		retval.SetMapIndex(reflect.Indirect(keyval), reflect.Indirect(valueval))
	}

	return nil
}

func wrapText(s string, l int, prefix string) string {
	// Basic text wrapping of s at spaces to fit in l
	var ret string

	s = strings.TrimSpace(s)

	for len(s) > l {
		// Try to split on space
		suffix := ""

		pos := strings.LastIndex(s[:l], " ")

		if pos < 0 {
			pos = l - 1
			suffix = "-\n"
		}

		if len(ret) != 0 {
			ret += "\n" + prefix
		}

		ret += strings.TrimSpace(s[:pos]) + suffix
		s = strings.TrimSpace(s[pos:])
	}

	if len(s) > 0 {
		if len(ret) != 0 {
			ret += "\n" + prefix
		}

		return ret + s
	}

	return ret
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"net/url"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func Test_extractTagNames(t *testing.T) {
	expext := []string{"tag1", "tag2", "tag2"}

	values := url.Values{}

	values.Add("tags[]", "tag1")
	values.Add("tags[]", "tag2")
	values.Add("tags[]", "tag2")

	assert.Equal(t, expext, extractTagNames(values))

	values.Del("tags[]")
	values.Set("tags", "tag1,tag2,tag2")

	assert.Equal(t, expext, extractTagNames(values))
}

func Test_buildCreateLogResponse(t *testing.T) {
	now := time.Now()
	tags := []Tag{Tag{1, "tag1"}, Tag{1, "tag2"}}

	logRecord := LogRecord{
		Id:          123,
		Application: Application{1, "TestApp"},
		Level:       5,
		CreatedAt:   &now,
		Message:     "Lorem ipsum",
		Tags:        tags,
	}

	res, _ := buildCreateLogResponse(&logRecord)

	parsed := LogRecordResponse{}
	json.Unmarshal(res, &parsed)

	fmt.Println(string(res[:]))
	fmt.Println(logRecord.CreatedAt)
	fmt.Println(parsed.CreatedAt)

	assert.Equal(t, 123, parsed.Id)
	assert.Equal(t, "TestApp", parsed.Application)
	assert.Equal(t, 5, parsed.Level)
	assert.EqualValues(t, now, *parsed.CreatedAt)
	assert.Equal(t, "Lorem ipsum", parsed.Message)
	assert.Equal(t, []string{"tag1", "tag2"}, parsed.Tags)
}

func Test_checkCreateLogParams(t *testing.T) {
	assert.Nil(t, checkCreateLogParams("Lorem", "1", []string{"tag1", "tag2"}))
	assert.Nil(t, checkCreateLogParams("Lorem", "1", []string{}))
	assert.Nil(t, checkCreateLogParams("Lorem", "5", []string{}))

	assert.Error(t, checkCreateLogParams("", "1", []string{}))
	assert.Error(t, checkCreateLogParams("Lorem", "", []string{}))
	assert.Error(t, checkCreateLogParams("Lorem", "0", []string{}))
	assert.Error(t, checkCreateLogParams("Lorem", "6", []string{}))
	assert.Error(t, checkCreateLogParams("Lorem", "1", []string{""}))
}

func Test_buildGetLogsResponse(t *testing.T) {
	now := time.Now()
	tags := []Tag{Tag{1, "tag1"}, Tag{1, "tag2"}}

	logRecords := []LogRecord{
		LogRecord{
			Id:          123,
			Application: Application{1, "TestApp"},
			Level:       5,
			CreatedAt:   &now,
			Message:     "Lorem ipsum",
			Tags:        tags,
		},
		LogRecord{
			Id:          456,
			Application: Application{1, "TestApp"},
			Level:       4,
			CreatedAt:   &now,
			Message:     "Dolor sit amet",
			Tags:        tags,
		},
	}

	res, _ := buildGetLogsResponse(&logRecords)

	parsed := LogRecordsResponse{}
	json.Unmarshal(res, &parsed)

	assert.Len(t, parsed, 2)

	for i, response := range parsed {
		assert.Equal(t, logRecords[i].Id, response.Id)
		assert.Equal(t, logRecords[i].Application.Name, response.Application)
		assert.Equal(t, logRecords[i].Level, response.Level)
		assert.EqualValues(t, now, *response.CreatedAt)
		assert.Equal(t, logRecords[i].Message, response.Message)
		assert.Equal(t, []string{"tag1", "tag2"}, response.Tags)
	}
}

func Test_checkGetLogParams(t *testing.T) {
	assert.Nil(t, checkGetLogParams("1", []string{"tag1", "tag2"}, "2014-01-02", "2014-03-04", "1"))
	assert.Nil(t, checkGetLogParams("1", []string{}, "2014-01-02", "2014-03-04", "1"))
	assert.Nil(t, checkGetLogParams("5", []string{}, "2014-01-02", "2014-03-04", "1"))
	assert.Nil(t, checkGetLogParams("1", []string{}, "2014-01-02 03:04:05", "2014-03-04 05:06:07", "1"))

	assert.Error(t, checkGetLogParams("", []string{}, "2014-01-02", "2014-03-04", "1"))
	assert.Error(t, checkGetLogParams("0", []string{}, "2014-01-02", "2014-03-04", "1"))
	assert.Error(t, checkGetLogParams("6", []string{}, "2014-01-02", "2014-03-04", "1"))
	assert.Error(t, checkGetLogParams("1", []string{""}, "2014-01-02", "2014-03-04", "1"))
	assert.Error(t, checkGetLogParams("1", []string{}, "2014-01-022", "2014-03-04", "1"))
	assert.Error(t, checkGetLogParams("1", []string{}, "2014-01-02", "2014-03-044", "1"))
	assert.Error(t, checkGetLogParams("1", []string{}, "2014-01-02", "2014-03-04", "a"))
}
<commit_msg>Debug info for travis<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"net/url"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func Test_extractTagNames(t *testing.T) {
	expext := []string{"tag1", "tag2", "tag2"}

	values := url.Values{}

	values.Add("tags[]", "tag1")
	values.Add("tags[]", "tag2")
	values.Add("tags[]", "tag2")

	assert.Equal(t, expext, extractTagNames(values))

	values.Del("tags[]")
	values.Set("tags", "tag1,tag2,tag2")

	assert.Equal(t, expext, extractTagNames(values))
}

func Test_buildCreateLogResponse(t *testing.T) {
	now := time.Now()
	tags := []Tag{Tag{1, "tag1"}, Tag{1, "tag2"}}

	logRecord := LogRecord{
		Id:          123,
		Application: Application{1, "TestApp"},
		Level:       5,
		CreatedAt:   &now,
		Message:     "Lorem ipsum",
		Tags:        tags,
	}

	res, _ := buildCreateLogResponse(&logRecord)

	parsed := LogRecordResponse{}
	json.Unmarshal(res, &parsed)

	fmt.Println(logRecord.CreatedAt.Zone())
	fmt.Println(parsed.CreatedAt.Zone())

	assert.Equal(t, 123, parsed.Id)
	assert.Equal(t, "TestApp", parsed.Application)
	assert.Equal(t, 5, parsed.Level)
	assert.EqualValues(t, now, *parsed.CreatedAt)
	assert.Equal(t, "Lorem ipsum", parsed.Message)
	assert.Equal(t, []string{"tag1", "tag2"}, parsed.Tags)
}

func Test_checkCreateLogParams(t *testing.T) {
	assert.Nil(t, checkCreateLogParams("Lorem", "1", []string{"tag1", "tag2"}))
	assert.Nil(t, checkCreateLogParams("Lorem", "1", []string{}))
	assert.Nil(t, checkCreateLogParams("Lorem", "5", []string{}))

	assert.Error(t, checkCreateLogParams("", "1", []string{}))
	assert.Error(t, checkCreateLogParams("Lorem", "", []string{}))
	assert.Error(t, checkCreateLogParams("Lorem", "0", []string{}))
	assert.Error(t, checkCreateLogParams("Lorem", "6", []string{}))
	assert.Error(t, checkCreateLogParams("Lorem", "1", []string{""}))
}

func Test_buildGetLogsResponse(t *testing.T) {
	now := time.Now()
	tags := []Tag{Tag{1, "tag1"}, Tag{1, "tag2"}}

	logRecords := []LogRecord{
		LogRecord{
			Id:          123,
			Application: Application{1, "TestApp"},
			Level:       5,
			CreatedAt:   &now,
			Message:     "Lorem ipsum",
			Tags:        tags,
		},
		LogRecord{
			Id:          456,
			Application: Application{1, "TestApp"},
			Level:       4,
			CreatedAt:   &now,
			Message:     "Dolor sit amet",
			Tags:        tags,
		},
	}

	res, _ := buildGetLogsResponse(&logRecords)

	parsed := LogRecordsResponse{}
	json.Unmarshal(res, &parsed)

	assert.Len(t, parsed, 2)

	for i, response := range parsed {
		assert.Equal(t, logRecords[i].Id, response.Id)
		assert.Equal(t, logRecords[i].Application.Name, response.Application)
		assert.Equal(t, logRecords[i].Level, response.Level)
		assert.EqualValues(t, now, *response.CreatedAt)
		assert.Equal(t, logRecords[i].Message, response.Message)
		assert.Equal(t, []string{"tag1", "tag2"}, response.Tags)
	}
}

func Test_checkGetLogParams(t *testing.T) {
	assert.Nil(t, checkGetLogParams("1", []string{"tag1", "tag2"}, "2014-01-02", "2014-03-04", "1"))
	assert.Nil(t, checkGetLogParams("1", []string{}, "2014-01-02", "2014-03-04", "1"))
	assert.Nil(t, checkGetLogParams("5", []string{}, "2014-01-02", "2014-03-04", "1"))
	assert.Nil(t, checkGetLogParams("1", []string{}, "2014-01-02 03:04:05", "2014-03-04 05:06:07", "1"))

	assert.Error(t, checkGetLogParams("", []string{}, "2014-01-02", "2014-03-04", "1"))
	assert.Error(t, checkGetLogParams("0", []string{}, "2014-01-02", "2014-03-04", "1"))
	assert.Error(t, checkGetLogParams("6", []string{}, "2014-01-02", "2014-03-04", "1"))
	assert.Error(t, checkGetLogParams("1", []string{""}, "2014-01-02", "2014-03-04", "1"))
	assert.Error(t, checkGetLogParams("1", []string{}, "2014-01-022", "2014-03-04", "1"))
	assert.Error(t, checkGetLogParams("1", []string{}, "2014-01-02", "2014-03-044", "1"))
	assert.Error(t, checkGetLogParams("1", []string{}, "2014-01-02", "2014-03-04", "a"))
}
<|endoftext|>


<commit_before>package gogame

/*
#cgo pkg-config: sdl2 SDL2_image
#include "SDL.h"
#include "SDL_image.h"

SDL_Texture * makeTexture( char *f, SDL_Renderer *ren ) {
    SDL_Texture *tex = IMG_LoadTexture(ren, f);
    return tex;
}

void renderGOOD( SDL_Renderer *ren, SDL_Texture *tex, int ox, int oy, int x, int y, int w, int h, int dw, int dh) {
    static SDL_Rect org;
    static SDL_Rect dst;
    org.x = ox;
    org.y = oy;
    org.w = w;
    org.h = h;
    dst.x = x;
    dst.y = y;
    dst.w = dw;
    dst.h = dh;
    SDL_RenderCopy(ren, tex, &org, &dst);
}

void queryTexture(SDL_Texture *t, int *h, int *v) {
    SDL_QueryTexture(t, NULL, NULL, h, v);
}

int intersects(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) {
    static SDL_Rect a;
    static SDL_Rect b;
    a.x = x1; a.y = y1; a.w = w1; a.h = h1;
    b.x = x2; b.y = y2; b.w = w2; b.h = h2;
    return SDL_HasIntersection(&a, &b);
}

*/
import "C"

type Drawable interface {
	BlitRect(*Rect)
	GetDimensions() (int, int)
}

type Texture struct {
	tex   *C.SDL_Texture
	realw int
	realh int
	dstw  int
	dsth  int
}

type Rect struct {
	X, Y, W, H int
}

// Set center of Rect to x,y
func (self *Rect) SetCenter(x, y int) {
	self.X = x - self.W/2
	self.Y = y - self.H/2
}

// Determine if two rectangles intersect
func (self *Rect) Intersects(r2 *Rect) bool {
	if 0 == C.intersects(C.int(self.X), C.int(self.Y), C.int(self.W), C.int(self.H),
		C.int(r2.X), C.int(r2.Y), C.int(r2.W), C.int(r2.H)) {
		return false
	}

	return true
}

// Construct a new texture from a image file
func NewTexture(filename string) *Texture {
	tex := C.makeTexture(C.CString(filename), renderer)
	return getNewTexture(tex)
}

func getNewTexture(tex *C.SDL_Texture) *Texture {
	t := new(Texture)
	t.tex = tex
	var w C.int
	var h C.int
	C.queryTexture(t.tex, &w, &h)
	t.realw, t.realh = int(w), int(h)
	t.dstw, t.dsth = t.realw, t.realh
	return t
}

func (self *Texture) SetDimensions(h, w int) {
	self.dstw = w
	self.dsth = h
}

// Destroy texture. Must be called explicitly, no automatic free for texture data
func (self *Texture) Destroy() {
	C.SDL_DestroyTexture(self.tex)
}

// Get texture dimensions, (horizontal, vertical)
func (self *Texture) GetDimensions() (int, int) {
	return self.dstw, self.dsth
}

func (self *Texture) Blit(x, y int) {
	C.renderGOOD(renderer, self.tex, C.int(0), C.int(0), C.int(x), C.int(y), C.int(self.realw),
		C.int(self.realh), C.int(self.dstw), C.int(self.dsth))
}

// Blit texture to screen, using provided rect
func (self *Texture) BlitRect(r *Rect) {
	C.renderGOOD(renderer, self.tex, C.int(0), C.int(0), C.int(r.X), C.int(r.Y), C.int(self.realw),
		C.int(self.realh), C.int(r.W), C.int(r.H))
}

// Get subtexture
func (self *Texture) SubTex(x, y, w, h int) *SubTexture {
	return &SubTexture{self, &Rect{x, y, w, h}, w, h}
}

type SubTexture struct {
	tex        *Texture
	rect       *Rect
	dstw, dsth int
}

func (self *SubTexture) SetDimensions(w, h int) {
	self.dstw = w
	self.dsth = h
}

func (self *SubTexture) Blit(x, y int) {
	C.renderGOOD(renderer, self.tex.tex, C.int(self.rect.X), C.int(self.rect.Y), C.int(x), C.int(y), C.int(self.rect.W),
		C.int(self.rect.H), C.int(self.dstw), C.int(self.dsth))
}

// Blit subtexture to screen, using provided rect
func (self *SubTexture) BlitRect(r *Rect) {
	C.renderGOOD(renderer, self.tex.tex, C.int(self.rect.X), C.int(self.rect.Y), C.int(r.X), C.int(r.Y), C.int(self.rect.W),
		C.int(self.rect.H), C.int(r.W), C.int(r.H))
}

// Get subtexture dimensions
func (self *SubTexture) GetDimensions() (int, int) {
	return self.rect.W, self.rect.H
}
<commit_msg>Anem fent<commit_after>package gogame

/*
#cgo pkg-config: sdl2 SDL2_image
#include "SDL.h"
#include "SDL_image.h"

SDL_Texture * makeTexture( char *f, SDL_Renderer *ren ) {
    SDL_Texture *tex = IMG_LoadTexture(ren, f);
    return tex;
}

void renderGOOD( SDL_Renderer *ren, SDL_Texture *tex, int ox, int oy, int x, int y, int w, int h, int dw, int dh) {
    static SDL_Rect org;
    static SDL_Rect dst;
    org.x = ox;
    org.y = oy;
    org.w = w;
    org.h = h;
    dst.x = x;
    dst.y = y;
    dst.w = dw;
    dst.h = dh;
    SDL_RenderCopy(ren, tex, &org, &dst);
}

void queryTexture(SDL_Texture *t, int *h, int *v) {
    SDL_QueryTexture(t, NULL, NULL, h, v);
}

int intersects(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) {
    static SDL_Rect a;
    static SDL_Rect b;
    a.x = x1; a.y = y1; a.w = w1; a.h = h1;
    b.x = x2; b.y = y2; b.w = w2; b.h = h2;
    return SDL_HasIntersection(&a, &b);
}

*/
import "C"

type Drawable interface {
	BlitRect(*Rect)
	GetDimensions() (int, int)
}

type Texture struct {
	tex   *C.SDL_Texture
	realw int
	realh int
	dstw  int
	dsth  int
}

type Rect struct {
	X, Y, W, H int
}

// Set center of Rect to x,y
func (self *Rect) SetCenter(x, y int) {
	self.X = x - self.W/2
	self.Y = y - self.H/2
}

func (self *Rect) GetCenter() (x, y int) {
	return self.X + self.W/2, self.Y + self.H/2
}

// Determine if two rectangles intersect
func (self *Rect) Intersects(r2 *Rect) bool {
	if 0 == C.intersects(C.int(self.X), C.int(self.Y), C.int(self.W), C.int(self.H),
		C.int(r2.X), C.int(r2.Y), C.int(r2.W), C.int(r2.H)) {
		return false
	}

	return true
}

// Construct a new texture from a image file
func NewTexture(filename string) *Texture {
	tex := C.makeTexture(C.CString(filename), renderer)
	return getNewTexture(tex)
}

func getNewTexture(tex *C.SDL_Texture) *Texture {
	t := new(Texture)
	t.tex = tex
	var w C.int
	var h C.int
	C.queryTexture(t.tex, &w, &h)
	t.realw, t.realh = int(w), int(h)
	t.dstw, t.dsth = t.realw, t.realh
	return t
}

func (self *Texture) SetDimensions(h, w int) {
	self.dstw = w
	self.dsth = h
}

// Destroy texture. Must be called explicitly, no automatic free for texture data
func (self *Texture) Destroy() {
	C.SDL_DestroyTexture(self.tex)
}

// Get texture dimensions, (horizontal, vertical)
func (self *Texture) GetDimensions() (int, int) {
	return self.dstw, self.dsth
}

func (self *Texture) Blit(x, y int) {
	C.renderGOOD(renderer, self.tex, C.int(0), C.int(0), C.int(x), C.int(y), C.int(self.realw),
		C.int(self.realh), C.int(self.dstw), C.int(self.dsth))
}

// Blit texture to screen, using provided rect
func (self *Texture) BlitRect(r *Rect) {
	C.renderGOOD(renderer, self.tex, C.int(0), C.int(0), C.int(r.X), C.int(r.Y), C.int(self.realw),
		C.int(self.realh), C.int(r.W), C.int(r.H))
}

// Get subtexture
func (self *Texture) SubTex(x, y, w, h int) *SubTexture {
	return &SubTexture{self, &Rect{x, y, w, h}, w, h}
}

type SubTexture struct {
	tex        *Texture
	rect       *Rect
	dstw, dsth int
}

func (self *SubTexture) SetDimensions(w, h int) {
	self.dstw = w
	self.dsth = h
}

func (self *SubTexture) Blit(x, y int) {
	C.renderGOOD(renderer, self.tex.tex, C.int(self.rect.X), C.int(self.rect.Y), C.int(x), C.int(y), C.int(self.rect.W),
		C.int(self.rect.H), C.int(self.dstw), C.int(self.dsth))
}

// Blit subtexture to screen, using provided rect
func (self *SubTexture) BlitRect(r *Rect) {
	C.renderGOOD(renderer, self.tex.tex, C.int(self.rect.X), C.int(self.rect.Y), C.int(r.X), C.int(r.Y), C.int(self.rect.W),
		C.int(self.rect.H), C.int(r.W), C.int(r.H))
}

// Get subtexture dimensions
func (self *SubTexture) GetDimensions() (int, int) {
	return self.rect.W, self.rect.H
}
<|endoftext|>


<commit_before>package tiff

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"math/big"
	"strings"
	"unicode"
	"unicode/utf8"
)

// TypeCategory specifies the category of a type.
type TypeCategory int

// Type categories.
const (
	IntVal TypeCategory = iota
	FloatVal
	RatVal
	StringVal
	UndefVal
	OtherVal
)

type DataType uint16

const (
	DTByte      DataType = 1
	DTAscii     DataType = 2
	DTShort     DataType = 3
	DTLong      DataType = 4
	DTRational  DataType = 5
	DTSByte     DataType = 6
	DTUndefined DataType = 7
	DTSShort    DataType = 8
	DTSLong     DataType = 9
	DTSRational DataType = 10
	DTFloat     DataType = 11
	DTDouble    DataType = 12
)

// typeSize specifies the size in bytes of each type.
var typeSize = map[DataType]uint32{
	DTByte:      1,
	DTAscii:     1,
	DTShort:     2,
	DTLong:      4,
	DTRational:  8,
	DTSByte:     1,
	DTUndefined: 1,
	DTSShort:    2,
	DTSLong:     4,
	DTSRational: 8,
	DTFloat:     4,
	DTDouble:    8,
}

// Tag reflects the parsed content of a tiff IFD tag.
type Tag struct {
	// Id is the 2-byte tiff tag identifier.
	Id uint16
	// Type is an integer (1 through 12) indicating the tag value's format.
	Type DataType
	// Count is the number of type Type stored in the tag's value (i.e. the
	// tag's value is an array of type Type and length Count).
	Count uint32
	// Val holds the bytes that represent the tag's value.
	Val []byte
	// ValOffset holds byte offset of the tag value w.r.t. the beginning of the
	// reader it was decoded from. Zero if the tag value fit inside the offset
	// field.
	ValOffset uint32

	order binary.ByteOrder

	intVals   []int64
	floatVals []float64
	ratVals   [][]int64
	strVal    string
}

// DecodeTag parses a tiff-encoded IFD tag from r and returns a Tag object. The
// first read from r should be the first byte of the tag. ReadAt offsets should
// generally be relative to the beginning of the tiff structure (not relative
// to the beginning of the tag).
func DecodeTag(r ReadAtReader, order binary.ByteOrder) (*Tag, error) {
	t := new(Tag)
	t.order = order

	err := binary.Read(r, order, &t.Id)
	if err != nil {
		return nil, errors.New("tiff: tag id read failed: " + err.Error())
	}

	err = binary.Read(r, order, &t.Type)
	if err != nil {
		return nil, errors.New("tiff: tag type read failed: " + err.Error())
	}

	err = binary.Read(r, order, &t.Count)
	if err != nil {
		return nil, errors.New("tiff: tag component count read failed: " + err.Error())
	}

	valLen := typeSize[t.Type] * t.Count
	if valLen > 4 {
		binary.Read(r, order, &t.ValOffset)
		t.Val = make([]byte, valLen)
		n, err := r.ReadAt(t.Val, int64(t.ValOffset))
		if n != int(valLen) || err != nil {
			return t, errors.New("tiff: tag value read failed: " + err.Error())
		}
	} else {
		val := make([]byte, valLen)
		if _, err = io.ReadFull(r, val); err != nil {
			return t, errors.New("tiff: tag offset read failed: " + err.Error())
		}
		// ignore padding.
		if _, err = io.ReadFull(r, make([]byte, 4-valLen)); err != nil {
			return t, errors.New("tiff: tag offset read failed: " + err.Error())
		}

		t.Val = val
	}

	t.convertVals()

	return t, nil
}

func (t *Tag) convertVals() {
	r := bytes.NewReader(t.Val)

	switch t.Type {
	case 2: // ascii string
		if len(t.Val) > 0 {
			t.strVal = string(t.Val[:len(t.Val)-1]) // ignore the last byte (NULL).
		}
	case 1:
		var v uint8
		t.intVals = make([]int64, int(t.Count))
		for i := range t.intVals {
			err := binary.Read(r, t.order, &v)
			panicOn(err)
			t.intVals[i] = int64(v)
		}
	case 3:
		var v uint16
		t.intVals = make([]int64, int(t.Count))
		for i := range t.intVals {
			err := binary.Read(r, t.order, &v)
			panicOn(err)
			t.intVals[i] = int64(v)
		}
	case 4:
		var v uint32
		t.intVals = make([]int64, int(t.Count))
		for i := range t.intVals {
			err := binary.Read(r, t.order, &v)
			panicOn(err)
			t.intVals[i] = int64(v)
		}
	case 6:
		var v int8
		t.intVals = make([]int64, int(t.Count))
		for i := range t.intVals {
			err := binary.Read(r, t.order, &v)
			panicOn(err)
			t.intVals[i] = int64(v)
		}
	case 8:
		var v int16
		t.intVals = make([]int64, int(t.Count))
		for i := range t.intVals {
			err := binary.Read(r, t.order, &v)
			panicOn(err)
			t.intVals[i] = int64(v)
		}
	case 9:
		var v int32
		t.intVals = make([]int64, int(t.Count))
		for i := range t.intVals {
			err := binary.Read(r, t.order, &v)
			panicOn(err)
			t.intVals[i] = int64(v)
		}
	case 5: // unsigned rational
		t.ratVals = make([][]int64, int(t.Count))
		for i := range t.ratVals {
			var n, d uint32
			err := binary.Read(r, t.order, &n)
			panicOn(err)
			err = binary.Read(r, t.order, &d)
			panicOn(err)
			t.ratVals[i] = []int64{int64(n), int64(d)}
		}
	case 10: // signed rational
		t.ratVals = make([][]int64, int(t.Count))
		for i := range t.ratVals {
			var n, d int32
			err := binary.Read(r, t.order, &n)
			panicOn(err)
			err = binary.Read(r, t.order, &d)
			panicOn(err)
			t.ratVals[i] = []int64{int64(n), int64(d)}
		}
	case 11: // float32
		t.floatVals = make([]float64, int(t.Count))
		for i := range t.floatVals {
			var v float32
			err := binary.Read(r, t.order, &v)
			panicOn(err)
			t.floatVals[i] = float64(v)
		}
	case 12: // float64 (double)
		t.floatVals = make([]float64, int(t.Count))
		for i := range t.floatVals {
			var u float64
			err := binary.Read(r, t.order, &u)
			panicOn(err)
			t.floatVals[i] = u
		}
	}
}

// Format returns a value indicating which method can be called to retrieve the
// tag's value properly typed (e.g. integer, rational, etc.).
func (t *Tag) TypeCategory() TypeCategory {
	switch t.Type {
	case 1, 3, 4, 6, 8, 9:
		return IntVal
	case 5, 10:
		return RatVal
	case 11, 12:
		return FloatVal
	case 2:
		return StringVal
	case 7:
		return UndefVal
	}
	return OtherVal
}

// Rat returns the tag's i'th value as a rational number. It panics if the tag format
// is not RatVal, if the denominator is zero, or if the tag has no i'th
// component. If a denominator could be zero, use Rat2.
func (t *Tag) Rat(i int) *big.Rat {
	n, d := t.Rat2(i)
	return big.NewRat(n, d)
}

// Rat2 returns the tag's i'th value as a rational number represented by a
// numerator-denominator pair. It panics if the tag format is not RatVal
// or if the tag value has no i'th component.
func (t *Tag) Rat2(i int) (num, den int64) {
	if t.TypeCategory() != RatVal {
		panic("Tag type category is not 'rational'")
	}
	return t.ratVals[i][0], t.ratVals[i][1]
}

// Int returns the tag's i'th value as an integer. It panics if the tag format is not
// IntVal or if the tag value has no i'th component.
func (t *Tag) Int(i int) int64 {
	if t.TypeCategory() != IntVal {
		panic("Tag type category is not 'int'")
	}
	return t.intVals[i]
}

// Float returns the tag's i'th value as a float. It panics if the tag format is not
// FloatVal or if the tag value has no i'th component.
func (t *Tag) Float(i int) float64 {
	if t.TypeCategory() != FloatVal {
		panic("Tag type category is not 'float'")
	}
	return t.floatVals[i]
}

// StringVal returns the tag's value as a string. It panics if the tag
// format is not StringVal
func (t *Tag) StringVal() string {
	if t.TypeCategory() != StringVal {
		panic("Tag type category is not 'ascii string'")
	}
	return t.strVal
}

// String returns a nicely formatted version of the tag.
func (t *Tag) String() string {
	data, err := t.MarshalJSON()
	panicOn(err)
	val := string(data)
	return fmt.Sprintf("{Id: %X, Val: %v}", t.Id, val)
}

func (t *Tag) MarshalJSON() ([]byte, error) {
	f := t.TypeCategory()

	switch f {
	case StringVal, UndefVal:
		return nullString(t.Val), nil
	case OtherVal:
		panic(fmt.Sprintf("Unhandled tag type=%v", t.Type))
	}

	rv := []string{}
	for i := 0; i < int(t.Count); i++ {
		switch f {
		case RatVal:
			n, d := t.Rat2(i)
			rv = append(rv, fmt.Sprintf(`"%v/%v"`, n, d))
		case FloatVal:
			rv = append(rv, fmt.Sprintf("%v", t.Float(i)))
		case IntVal:
			rv = append(rv, fmt.Sprintf("%v", t.Int(i)))
		}
	}
	return []byte(fmt.Sprintf(`[%s]`, strings.Join(rv, ","))), nil
}

func nullString(in []byte) []byte {
	rv := bytes.Buffer{}
	rv.WriteByte('"')
	for _, b := range in {
		if unicode.IsPrint(rune(b)) {
			rv.WriteByte(b)
		}
	}
	rv.WriteByte('"')
	rvb := rv.Bytes()
	if utf8.Valid(rvb) {
		return rvb
	}
	return []byte(`""`)
}

func panicOn(err error) {
	if err != nil {
		panic("unexpected error: " + err.Error())
	}
}
<commit_msg>Update covnertVals and TypeCategory to use new constants for DataType<commit_after>package tiff

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"math/big"
	"strings"
	"unicode"
	"unicode/utf8"
)

// TypeCategory specifies the category of a type.
type TypeCategory int

// Type categories.
const (
	IntVal TypeCategory = iota
	FloatVal
	RatVal
	StringVal
	UndefVal
	OtherVal
)

type DataType uint16

const (
	DTByte      DataType = 1
	DTAscii     DataType = 2
	DTShort     DataType = 3
	DTLong      DataType = 4
	DTRational  DataType = 5
	DTSByte     DataType = 6
	DTUndefined DataType = 7
	DTSShort    DataType = 8
	DTSLong     DataType = 9
	DTSRational DataType = 10
	DTFloat     DataType = 11
	DTDouble    DataType = 12
)

// typeSize specifies the size in bytes of each type.
var typeSize = map[DataType]uint32{
	DTByte:      1,
	DTAscii:     1,
	DTShort:     2,
	DTLong:      4,
	DTRational:  8,
	DTSByte:     1,
	DTUndefined: 1,
	DTSShort:    2,
	DTSLong:     4,
	DTSRational: 8,
	DTFloat:     4,
	DTDouble:    8,
}

// Tag reflects the parsed content of a tiff IFD tag.
type Tag struct {
	// Id is the 2-byte tiff tag identifier.
	Id uint16
	// Type is an integer (1 through 12) indicating the tag value's format.
	Type DataType
	// Count is the number of type Type stored in the tag's value (i.e. the
	// tag's value is an array of type Type and length Count).
	Count uint32
	// Val holds the bytes that represent the tag's value.
	Val []byte
	// ValOffset holds byte offset of the tag value w.r.t. the beginning of the
	// reader it was decoded from. Zero if the tag value fit inside the offset
	// field.
	ValOffset uint32

	order binary.ByteOrder

	intVals   []int64
	floatVals []float64
	ratVals   [][]int64
	strVal    string
}

// DecodeTag parses a tiff-encoded IFD tag from r and returns a Tag object. The
// first read from r should be the first byte of the tag. ReadAt offsets should
// generally be relative to the beginning of the tiff structure (not relative
// to the beginning of the tag).
func DecodeTag(r ReadAtReader, order binary.ByteOrder) (*Tag, error) {
	t := new(Tag)
	t.order = order

	err := binary.Read(r, order, &t.Id)
	if err != nil {
		return nil, errors.New("tiff: tag id read failed: " + err.Error())
	}

	err = binary.Read(r, order, &t.Type)
	if err != nil {
		return nil, errors.New("tiff: tag type read failed: " + err.Error())
	}

	err = binary.Read(r, order, &t.Count)
	if err != nil {
		return nil, errors.New("tiff: tag component count read failed: " + err.Error())
	}

	valLen := typeSize[t.Type] * t.Count
	if valLen > 4 {
		binary.Read(r, order, &t.ValOffset)
		t.Val = make([]byte, valLen)
		n, err := r.ReadAt(t.Val, int64(t.ValOffset))
		if n != int(valLen) || err != nil {
			return t, errors.New("tiff: tag value read failed: " + err.Error())
		}
	} else {
		val := make([]byte, valLen)
		if _, err = io.ReadFull(r, val); err != nil {
			return t, errors.New("tiff: tag offset read failed: " + err.Error())
		}
		// ignore padding.
		if _, err = io.ReadFull(r, make([]byte, 4-valLen)); err != nil {
			return t, errors.New("tiff: tag offset read failed: " + err.Error())
		}

		t.Val = val
	}

	t.convertVals()

	return t, nil
}

func (t *Tag) convertVals() {
	r := bytes.NewReader(t.Val)

	switch t.Type {
	case DTAscii:
		if len(t.Val) > 0 {
			t.strVal = string(t.Val[:len(t.Val)-1]) // ignore the last byte (NULL).
		}
	case DTByte:
		var v uint8
		t.intVals = make([]int64, int(t.Count))
		for i := range t.intVals {
			err := binary.Read(r, t.order, &v)
			panicOn(err)
			t.intVals[i] = int64(v)
		}
	case DTShort:
		var v uint16
		t.intVals = make([]int64, int(t.Count))
		for i := range t.intVals {
			err := binary.Read(r, t.order, &v)
			panicOn(err)
			t.intVals[i] = int64(v)
		}
	case DTLong:
		var v uint32
		t.intVals = make([]int64, int(t.Count))
		for i := range t.intVals {
			err := binary.Read(r, t.order, &v)
			panicOn(err)
			t.intVals[i] = int64(v)
		}
	case DTSByte:
		var v int8
		t.intVals = make([]int64, int(t.Count))
		for i := range t.intVals {
			err := binary.Read(r, t.order, &v)
			panicOn(err)
			t.intVals[i] = int64(v)
		}
	case DTSShort:
		var v int16
		t.intVals = make([]int64, int(t.Count))
		for i := range t.intVals {
			err := binary.Read(r, t.order, &v)
			panicOn(err)
			t.intVals[i] = int64(v)
		}
	case DTSLong:
		var v int32
		t.intVals = make([]int64, int(t.Count))
		for i := range t.intVals {
			err := binary.Read(r, t.order, &v)
			panicOn(err)
			t.intVals[i] = int64(v)
		}
	case DTRational:
		t.ratVals = make([][]int64, int(t.Count))
		for i := range t.ratVals {
			var n, d uint32
			err := binary.Read(r, t.order, &n)
			panicOn(err)
			err = binary.Read(r, t.order, &d)
			panicOn(err)
			t.ratVals[i] = []int64{int64(n), int64(d)}
		}
	case DTSRational:
		t.ratVals = make([][]int64, int(t.Count))
		for i := range t.ratVals {
			var n, d int32
			err := binary.Read(r, t.order, &n)
			panicOn(err)
			err = binary.Read(r, t.order, &d)
			panicOn(err)
			t.ratVals[i] = []int64{int64(n), int64(d)}
		}
	case DTFloat: // float32
		t.floatVals = make([]float64, int(t.Count))
		for i := range t.floatVals {
			var v float32
			err := binary.Read(r, t.order, &v)
			panicOn(err)
			t.floatVals[i] = float64(v)
		}
	case DTDouble:
		t.floatVals = make([]float64, int(t.Count))
		for i := range t.floatVals {
			var u float64
			err := binary.Read(r, t.order, &u)
			panicOn(err)
			t.floatVals[i] = u
		}
	}
}

// Format returns a value indicating which method can be called to retrieve the
// tag's value properly typed (e.g. integer, rational, etc.).
func (t *Tag) TypeCategory() TypeCategory {
	switch t.Type {
	case DTByte, DTShort, DTLong, DTSByte, DTSShort, DTSLong:
		return IntVal
	case DTRational, DTSRational:
		return RatVal
	case DTFloat, DTDouble:
		return FloatVal
	case DTAscii:
		return StringVal
	case DTUndefined:
		return UndefVal
	}
	return OtherVal
}

// Rat returns the tag's i'th value as a rational number. It panics if the tag format
// is not RatVal, if the denominator is zero, or if the tag has no i'th
// component. If a denominator could be zero, use Rat2.
func (t *Tag) Rat(i int) *big.Rat {
	n, d := t.Rat2(i)
	return big.NewRat(n, d)
}

// Rat2 returns the tag's i'th value as a rational number represented by a
// numerator-denominator pair. It panics if the tag format is not RatVal
// or if the tag value has no i'th component.
func (t *Tag) Rat2(i int) (num, den int64) {
	if t.TypeCategory() != RatVal {
		panic("Tag type category is not 'rational'")
	}
	return t.ratVals[i][0], t.ratVals[i][1]
}

// Int returns the tag's i'th value as an integer. It panics if the tag format is not
// IntVal or if the tag value has no i'th component.
func (t *Tag) Int(i int) int64 {
	if t.TypeCategory() != IntVal {
		panic("Tag type category is not 'int'")
	}
	return t.intVals[i]
}

// Float returns the tag's i'th value as a float. It panics if the tag format is not
// FloatVal or if the tag value has no i'th component.
func (t *Tag) Float(i int) float64 {
	if t.TypeCategory() != FloatVal {
		panic("Tag type category is not 'float'")
	}
	return t.floatVals[i]
}

// StringVal returns the tag's value as a string. It panics if the tag
// format is not StringVal
func (t *Tag) StringVal() string {
	if t.TypeCategory() != StringVal {
		panic("Tag type category is not 'ascii string'")
	}
	return t.strVal
}

// String returns a nicely formatted version of the tag.
func (t *Tag) String() string {
	data, err := t.MarshalJSON()
	panicOn(err)
	val := string(data)
	return fmt.Sprintf("{Id: %X, Val: %v}", t.Id, val)
}

func (t *Tag) MarshalJSON() ([]byte, error) {
	f := t.TypeCategory()

	switch f {
	case StringVal, UndefVal:
		return nullString(t.Val), nil
	case OtherVal:
		panic(fmt.Sprintf("Unhandled tag type=%v", t.Type))
	}

	rv := []string{}
	for i := 0; i < int(t.Count); i++ {
		switch f {
		case RatVal:
			n, d := t.Rat2(i)
			rv = append(rv, fmt.Sprintf(`"%v/%v"`, n, d))
		case FloatVal:
			rv = append(rv, fmt.Sprintf("%v", t.Float(i)))
		case IntVal:
			rv = append(rv, fmt.Sprintf("%v", t.Int(i)))
		}
	}
	return []byte(fmt.Sprintf(`[%s]`, strings.Join(rv, ","))), nil
}

func nullString(in []byte) []byte {
	rv := bytes.Buffer{}
	rv.WriteByte('"')
	for _, b := range in {
		if unicode.IsPrint(rune(b)) {
			rv.WriteByte(b)
		}
	}
	rv.WriteByte('"')
	rvb := rv.Bytes()
	if utf8.Valid(rvb) {
		return rvb
	}
	return []byte(`""`)
}

func panicOn(err error) {
	if err != nil {
		panic("unexpected error: " + err.Error())
	}
}
<|endoftext|>


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

package router

import (
	"compress/gzip"
	"encoding/json"
	"net/http"
	"strings"
	"time"
)

// Default content types
const (
	// MIMEJSON - "Content-type" for JSON
	MIMEJSON = "application/json"
	// MIMETEXT - "Content-type" for TEXT
	MIMETEXT = "text/plain"
)

// Control allows us to pass variables between middleware,
// assign Http codes and render a Body.
type Control struct {

	// Request is an adapter which allows the usage of a http.Request as standard request
	Request *http.Request

	// Writer is an adapter which allows the usage of a http.ResponseWriter as standard writer
	Writer http.ResponseWriter

	// User content type
	ContentType string

	// Code of HTTP status
	code int

	// compactJSON propery defines JSON output format (default is not compact)
	compactJSON bool

	// if used, json header shows meta data
	useMetaData bool

	// header with metadata
	header Header

	// errors
	errorHeader ErrorHeader
	errors      []Error

	// Params is set of parameters
	Params []Param

	// timer used to calculate a elapsed time for handler and writing it in a response
	timer time.Time
}

// Param is a URL parameter which represents as key and value.
type Param struct {
	Key   string
	Value string
}

// Header is used to prepare a JSON header with meta data
type Header struct {
	Duration   time.Duration `json:"duration,omitempty"`
	Took       string        `json:"took,omitempty"`
	APIVersion string        `json:"apiVersion,omitempty"`
	Context    string        `json:"context,omitempty"`
	ID         string        `json:"id,omitempty"`
	Method     string        `json:"method,omitempty"`
	Params     interface{}   `json:"params,omitempty"`
	Data       interface{}   `json:"data,omitempty"`
	Error      interface{}   `json:"error,omitempty"`
}

type ErrorHeader struct {
	Code    uint16      `json:"code,omitempty"`
	Message string      `json:"message,omitempty"`
	Errors  interface{} `json:"errors,omitempty"`
}

type Error struct {
	Domain       string `json:"domain,omitempty"`
	Reason       string `json:"reason,omitempty"`
	Location     string `json:"location,omitempty"`
	LocationType string `json:"locationType,omitempty"`
	ExtendedHelp string `json:"extendedHelp,omitempty"`
	SendReport   string `json:"sendReport,omitempty"`
}

// Get returns the first value associated with the given name.
// If there are no values associated with the key, an empty string is returned.
func (c *Control) Get(name string) string {
	for idx := range c.Params {
		if c.Params[idx].Key == name {
			return c.Params[idx].Value
		}
	}

	return c.Request.URL.Query().Get(name)
}

// Set adds new parameters which represents as set of key/value.
func (c *Control) Set(params []Param) {
	c.Params = append(c.Params, params...)
}

// Code assigns http status code, which returns on http request
func (c *Control) Code(code int) *Control {
	if code >= 200 && code < 600 {
		c.code = code
	}
	return c
}

// CompactJSON change JSON output format (default mode is false)
func (c *Control) CompactJSON(mode bool) *Control {
	c.compactJSON = mode
	return c
}

// UseMetaData shows meta data in JSON Header
func (c *Control) UseMetaData() *Control {
	c.useMetaData = true
	return c
}

// APIVersion add API version meta data
func (c *Control) APIVersion(version string) *Control {
	c.useMetaData = true
	c.header.APIVersion = version
	return c
}

// Context add context meta data
func (c *Control) Context(context string) *Control {
	c.useMetaData = true
	c.header.Context = context
	return c
}

// ID add id meta data
func (c *Control) ID(id string) *Control {
	c.useMetaData = true
	c.header.ID = id
	return c
}

// Method add method meta data
func (c *Control) Method(method string) *Control {
	c.useMetaData = true
	c.header.Method = method
	return c
}

func (c *Control) produceError(code uint16, message string) *Control {
	c.useMetaData = true
	c.errorHeader.Code = code
	c.errorHeader.Message = message
	return c
}

func (c *Control) AddError(errors ...Error) *Control {
	c.useMetaData = true
	c.errors = append(c.errors, errors...)
	return c
}

// UseTimer allow caalculate elapsed time of request handling
func (c *Control) UseTimer() {
	c.useMetaData = true
	c.timer = time.Now()
}

// Body renders the given data into the response body
func (c *Control) Body(data interface{}) {
	var content []byte

	if str, ok := data.(string); ok {
		content = []byte(str)
		if c.ContentType != "" {
			c.Writer.Header().Add("Content-type", c.ContentType)
		} else {
			c.Writer.Header().Add("Content-type", MIMETEXT)
		}
	} else {
		if c.useMetaData {
			c.header.Data = data
			if !c.timer.IsZero() {
				took := time.Now()
				c.header.Duration = took.Sub(c.timer)
				c.header.Took = took.Sub(c.timer).String()
			}
			if len(c.Params) > 0 {
				c.header.Params = c.Params
			}
			if c.errorHeader.Code != 0 || c.errorHeader.Message != "" || len(c.errors) > 0 {
				if len(c.errors) > 0 {
					c.errorHeader.Errors = c.errors
				}
				c.header.Error = c.errorHeader
			}
			data = c.header
		}
		var err error
		if c.compactJSON {
			content, err = json.Marshal(data)
		} else {
			content, err = json.MarshalIndent(data, "", "  ")
		}
		if err != nil {
			c.Writer.WriteHeader(http.StatusInternalServerError)
			return
		}
		c.Writer.Header().Add("Content-type", MIMEJSON)
	}
	if strings.Contains(c.Request.Header.Get("Accept-Encoding"), "gzip") {
		c.Writer.Header().Add("Content-Encoding", "gzip")
		if c.code > 0 {
			c.Writer.WriteHeader(c.code)
		}
		gz := gzip.NewWriter(c.Writer)
		gz.Write(content)
		gz.Close()
	} else {
		if c.code > 0 {
			c.Writer.WriteHeader(c.code)
		}
		c.Writer.Write(content)
	}
}
<commit_msg>alternative params<commit_after>// Copyright 2015 Igor Dolzhikov. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package router

import (
	"compress/gzip"
	"encoding/json"
	"net/http"
	"strings"
	"time"
)

// Default content types
const (
	// MIMEJSON - "Content-type" for JSON
	MIMEJSON = "application/json"
	// MIMETEXT - "Content-type" for TEXT
	MIMETEXT = "text/plain"
)

// Control allows us to pass variables between middleware,
// assign Http codes and render a Body.
type Control struct {

	// Request is an adapter which allows the usage of a http.Request as standard request
	Request *http.Request

	// Writer is an adapter which allows the usage of a http.ResponseWriter as standard writer
	Writer http.ResponseWriter

	// User content type
	ContentType string

	// Code of HTTP status
	code int

	// compactJSON propery defines JSON output format (default is not compact)
	compactJSON bool

	// if used, json header shows meta data
	useMetaData bool

	// header with metadata
	header Header

	// errors
	errorHeader ErrorHeader

	// params is set of key/value parameters
	params []Param

	// timer used to calculate a elapsed time for handler and writing it in a response
	timer time.Time
}

// Param is a URL parameter which represents as key and value.
type Param struct {
	Key   string `json:"key,omitempty"`
	Value string `json:"value,omitempty"`
}

// Header is used to prepare a JSON header with meta data
type Header struct {
	Duration   time.Duration `json:"duration,omitempty"`
	Took       string        `json:"took,omitempty"`
	APIVersion string        `json:"apiVersion,omitempty"`
	Context    string        `json:"context,omitempty"`
	ID         string        `json:"id,omitempty"`
	Method     string        `json:"method,omitempty"`
	Params     interface{}   `json:"params,omitempty"`
	Data       interface{}   `json:"data,omitempty"`
	Error      interface{}   `json:"error,omitempty"`
}

// ErrorHeader contains error code, message and array of specified error reports
type ErrorHeader struct {
	Code    uint16  `json:"code,omitempty"`
	Message string  `json:"message,omitempty"`
	Errors  []Error `json:"errors,omitempty"`
}

// Error report format
type Error struct {
	Domain       string `json:"domain,omitempty"`
	Reason       string `json:"reason,omitempty"`
	Message      string `json:"message,omitempty"`
	Location     string `json:"location,omitempty"`
	LocationType string `json:"locationType,omitempty"`
	ExtendedHelp string `json:"extendedHelp,omitempty"`
	SendReport   string `json:"sendReport,omitempty"`
}

// Get returns the first value associated with the given name.
// If there are no values associated with the key, an empty string is returned.
func (c *Control) Get(name string) string {
	for idx := range c.params {
		if c.params[idx].Key == name {
			return c.params[idx].Value
		}
	}

	return c.Request.URL.Query().Get(name)
}

// Set adds new parameters which represents as set of key/value.
func (c *Control) Set(params ...Param) *Control {
	c.params = append(c.params, params...)
	return c
}

// Code assigns http status code, which returns on http request
func (c *Control) Code(code int) *Control {
	if code >= 200 && code < 600 {
		c.code = code
	}
	return c
}

// CompactJSON change JSON output format (default mode is false)
func (c *Control) CompactJSON(mode bool) *Control {
	c.compactJSON = mode
	return c
}

// UseMetaData shows meta data in JSON Header
func (c *Control) UseMetaData() *Control {
	c.useMetaData = true
	return c
}

// APIVersion add API version meta data
func (c *Control) APIVersion(version string) *Control {
	c.useMetaData = true
	c.header.APIVersion = version
	return c
}

// Context add context meta data
func (c *Control) Context(context string) *Control {
	c.useMetaData = true
	c.header.Context = context
	return c
}

// ID add id meta data
func (c *Control) ID(id string) *Control {
	c.useMetaData = true
	c.header.ID = id
	return c
}

// Method add method meta data
func (c *Control) Method(method string) *Control {
	c.useMetaData = true
	c.header.Method = method
	return c
}

// AlternativeParams add params meta data in alternative format
func (c *Control) AlternativeParams(params interface{}) *Control {
	c.useMetaData = true
	c.header.Params = params
	return c
}

func (c *Control) produceError(code uint16, message string) *Control {
	c.useMetaData = true
	c.errorHeader.Code = code
	c.errorHeader.Message = message
	return c
}

func (c *Control) AddError(errors ...Error) *Control {
	c.useMetaData = true
	c.errorHeader.Errors = append(c.errorHeader.Errors, errors...)
	return c
}

// UseTimer allow caalculate elapsed time of request handling
func (c *Control) UseTimer() {
	c.useMetaData = true
	c.timer = time.Now()
}

// Body renders the given data into the response body
func (c *Control) Body(data interface{}) {
	var content []byte

	if str, ok := data.(string); ok {
		content = []byte(str)
		if c.ContentType != "" {
			c.Writer.Header().Add("Content-type", c.ContentType)
		} else {
			c.Writer.Header().Add("Content-type", MIMETEXT)
		}
	} else {
		if c.useMetaData {
			c.header.Data = data
			if !c.timer.IsZero() {
				took := time.Now()
				c.header.Duration = took.Sub(c.timer)
				c.header.Took = took.Sub(c.timer).String()
			}
			if c.header.Params == nil && len(c.params) > 0 {
				c.header.Params = c.params
			}
			if c.errorHeader.Code != 0 || c.errorHeader.Message != "" || len(c.errorHeader.Errors) > 0 {
				c.header.Error = c.errorHeader
			}
			data = c.header
		}
		var err error
		if c.compactJSON {
			content, err = json.Marshal(data)
		} else {
			content, err = json.MarshalIndent(data, "", "  ")
		}
		if err != nil {
			c.Writer.WriteHeader(http.StatusInternalServerError)
			return
		}
		c.Writer.Header().Add("Content-type", MIMEJSON)
	}
	if strings.Contains(c.Request.Header.Get("Accept-Encoding"), "gzip") {
		c.Writer.Header().Add("Content-Encoding", "gzip")
		if c.code > 0 {
			c.Writer.WriteHeader(c.code)
		}
		gz := gzip.NewWriter(c.Writer)
		gz.Write(content)
		gz.Close()
	} else {
		if c.code > 0 {
			c.Writer.WriteHeader(c.code)
		}
		c.Writer.Write(content)
	}
}
<|endoftext|>