<commit_before>package dexcom

import (
	"fmt"
	"time"
)

type Record interface {
	Type() RecordType
	Unmarshal([]byte) error
}

func Unmarshal(v []byte, record Record) error {
	return record.Unmarshal(v)
}

// A SensorRecord contains a reading received from a Dexcom CGM sensor.
type SensorRecord struct {
	Timestamp  Timestamp
	Unfiltered uint32
	Filtered   uint32
	RSSI       uint16
}

func (r *SensorRecord) Type() RecordType {
	return SENSOR_DATA
}

func (r *SensorRecord) Unmarshal(v []byte) error {
	if len(v) != 18 {
		return fmt.Errorf("SensorRecord: wrong length (%d)", len(v))
	}
	Unmarshal(v[0:8], &r.Timestamp)
	r.Unfiltered = UnmarshalUint32(v[8:12])
	r.Filtered = UnmarshalUint32(v[12:16])
	r.RSSI = UnmarshalUint16(v[16:18])
	return nil
}

// SpecialGlucose values are used to encode various exceptional conditions.
type SpecialGlucose uint16

//go:generate stringer -type=SpecialGlucose

const (
	SENSOR_NOT_ACTIVE SpecialGlucose = 1 + iota
	MINIMAL_DEVIATION
	NO_ANTENNA
	_
	SENSOR_NOT_CALIBRATED
	COUNTS_DEVIATION
	_
	_
	ABSOLUTE_DEVIATION
	POWER_DEVIATION
	_
	BAD_RF
	specialLimit
)

// IsSpecial checks whether a glucose value falls in the SpecialGlucose range.
func IsSpecial(glucose uint16) bool {
	return glucose < uint16(specialLimit)
}

// The Trend type represents the directional arrows
// displayed by the Dexcom CGM receiver.
type Trend byte

//go:generate stringer -type=Trend

const (
	UP_UP Trend = 1 + iota
	UP
	UP_45
	FLAT
	DOWN_45
	DOWN
	DOWN_DOWN
	NOT_COMPUTABLE
	OUT_OF_RANGE
)

var trendSymbol = map[Trend]string{
	UP_UP:          "⇈",
	UP:             "↑",
	UP_45:          "↗",
	FLAT:           "→",
	DOWN_45:        "↘",
	DOWN:           "↓",
	DOWN_DOWN:      "⇊",
	NOT_COMPUTABLE: "⁇",
	OUT_OF_RANGE:   "⋯",
}

// Symbol returns the arrow symbol corresponding to a Trend value.
func (t Trend) Symbol() string {
	return trendSymbol[t]
}

// An EGVRecord contains a glucose reading calculated by the Dexcom CGM receiver.
type EGVRecord struct {
	Timestamp   Timestamp
	Glucose     uint16
	DisplayOnly bool
	Trend       Trend
}

const (
	EGV_DISPLAY_ONLY     = 1 << 15
	EGV_VALUE_MASK       = 1<<10 - 1
	EGV_TREND_ARROW_MASK = 1<<4 - 1
)

func (r *EGVRecord) Type() RecordType {
	return EGV_DATA
}

func (r *EGVRecord) Unmarshal(v []byte) error {
	if len(v) != 11 {
		return fmt.Errorf("EGVRecord: wrong length (%d)", len(v))
	}
	Unmarshal(v[0:8], &r.Timestamp)
	g := UnmarshalUint16(v[8:10])
	r.Glucose = g & EGV_VALUE_MASK
	r.DisplayOnly = g&EGV_DISPLAY_ONLY != 0
	r.Trend = Trend(v[10] & EGV_TREND_ARROW_MASK)
	return nil
}

// A MeterRecord contains a glucometer reading.
type MeterRecord struct {
	Timestamp Timestamp
	Glucose   uint16
	MeterTime time.Time
}

func (r *MeterRecord) Type() RecordType {
	return METER_DATA
}

func (r *MeterRecord) Unmarshal(v []byte) error {
	if len(v) != 14 {
		panic(fmt.Sprintf("MeterRecord: wrong length (%d)", len(v)))
	}
	Unmarshal(v[0:8], &r.Timestamp)
	r.Glucose = UnmarshalUint16(v[8:10])
	r.MeterTime = UnmarshalTime(v[10:14])
	return nil
}
<commit_msg>Change panic to error return<commit_after>package dexcom

import (
	"fmt"
	"time"
)

type Record interface {
	Type() RecordType
	Unmarshal([]byte) error
}

func Unmarshal(v []byte, record Record) error {
	return record.Unmarshal(v)
}

// A SensorRecord contains a reading received from a Dexcom CGM sensor.
type SensorRecord struct {
	Timestamp  Timestamp
	Unfiltered uint32
	Filtered   uint32
	RSSI       uint16
}

func (r *SensorRecord) Type() RecordType {
	return SENSOR_DATA
}

func (r *SensorRecord) Unmarshal(v []byte) error {
	if len(v) != 18 {
		return fmt.Errorf("SensorRecord: wrong length (%d)", len(v))
	}
	Unmarshal(v[0:8], &r.Timestamp)
	r.Unfiltered = UnmarshalUint32(v[8:12])
	r.Filtered = UnmarshalUint32(v[12:16])
	r.RSSI = UnmarshalUint16(v[16:18])
	return nil
}

// SpecialGlucose values are used to encode various exceptional conditions.
type SpecialGlucose uint16

//go:generate stringer -type=SpecialGlucose

const (
	SENSOR_NOT_ACTIVE SpecialGlucose = 1 + iota
	MINIMAL_DEVIATION
	NO_ANTENNA
	_
	SENSOR_NOT_CALIBRATED
	COUNTS_DEVIATION
	_
	_
	ABSOLUTE_DEVIATION
	POWER_DEVIATION
	_
	BAD_RF
	specialLimit
)

// IsSpecial checks whether a glucose value falls in the SpecialGlucose range.
func IsSpecial(glucose uint16) bool {
	return glucose < uint16(specialLimit)
}

// The Trend type represents the directional arrows
// displayed by the Dexcom CGM receiver.
type Trend byte

//go:generate stringer -type=Trend

const (
	UP_UP Trend = 1 + iota
	UP
	UP_45
	FLAT
	DOWN_45
	DOWN
	DOWN_DOWN
	NOT_COMPUTABLE
	OUT_OF_RANGE
)

var trendSymbol = map[Trend]string{
	UP_UP:          "⇈",
	UP:             "↑",
	UP_45:          "↗",
	FLAT:           "→",
	DOWN_45:        "↘",
	DOWN:           "↓",
	DOWN_DOWN:      "⇊",
	NOT_COMPUTABLE: "⁇",
	OUT_OF_RANGE:   "⋯",
}

// Symbol returns the arrow symbol corresponding to a Trend value.
func (t Trend) Symbol() string {
	return trendSymbol[t]
}

// An EGVRecord contains a glucose reading calculated by the Dexcom CGM receiver.
type EGVRecord struct {
	Timestamp   Timestamp
	Glucose     uint16
	DisplayOnly bool
	Trend       Trend
}

const (
	EGV_DISPLAY_ONLY     = 1 << 15
	EGV_VALUE_MASK       = 1<<10 - 1
	EGV_TREND_ARROW_MASK = 1<<4 - 1
)

func (r *EGVRecord) Type() RecordType {
	return EGV_DATA
}

func (r *EGVRecord) Unmarshal(v []byte) error {
	if len(v) != 11 {
		return fmt.Errorf("EGVRecord: wrong length (%d)", len(v))
	}
	Unmarshal(v[0:8], &r.Timestamp)
	g := UnmarshalUint16(v[8:10])
	r.Glucose = g & EGV_VALUE_MASK
	r.DisplayOnly = g&EGV_DISPLAY_ONLY != 0
	r.Trend = Trend(v[10] & EGV_TREND_ARROW_MASK)
	return nil
}

// A MeterRecord contains a glucometer reading.
type MeterRecord struct {
	Timestamp Timestamp
	Glucose   uint16
	MeterTime time.Time
}

func (r *MeterRecord) Type() RecordType {
	return METER_DATA
}

func (r *MeterRecord) Unmarshal(v []byte) error {
	if len(v) != 14 {
		return fmt.Errorf("MeterRecord: wrong length (%d)", len(v))
	}
	Unmarshal(v[0:8], &r.Timestamp)
	r.Glucose = UnmarshalUint16(v[8:10])
	r.MeterTime = UnmarshalTime(v[10:14])
	return nil
}
<|endoftext|>


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

package network

//go:generate mockgen -source $GOFILE -package=$GOPACKAGE -destination=generated_mock_$GOFILE

/*
 ATTENTION: Rerun code generators when interface signatures are modified.
*/

import (
	"fmt"

	v1 "kubevirt.io/client-go/api/v1"
	"kubevirt.io/kubevirt/pkg/virt-launcher/virtwrap/api"
)

const podInterface = "eth0"

var interfaceCacheFile = "/var/run/kubevirt/interface-cache-%s-%s.json"
var qemuArgCacheFile = "/var/run/kubevirt/qemu-arg-%s-%s.json"
var vifCacheFile = "/var/run/kubevirt/vif-cache-%s-%s.json"
var NetworkInterfaceFactory = getNetworkClass

var podInterfaceName = podInterface

type plugFunction func(vif NetworkInterface, vmi *v1.VirtualMachineInstance, iface *v1.Interface, network *v1.Network, domain *api.Domain, podInterfaceName string) error

type NetworkInterface interface {
	PlugPhase1(vmi *v1.VirtualMachineInstance, iface *v1.Interface, network *v1.Network, domain *api.Domain, podInterfaceName string) error
	PlugPhase2(vmi *v1.VirtualMachineInstance, iface *v1.Interface, network *v1.Network, domain *api.Domain, podInterfaceName string) error
	Unplug()
}

func SetupNetworkInterfacesPhase1(vmi *v1.VirtualMachineInstance, domain *api.Domain) error {
	return _setupNetworkInterfaces(vmi, domain, NetworkInterface.PlugPhase1)
}

func SetupNetworkInterfacesPhase2(vmi *v1.VirtualMachineInstance, domain *api.Domain) error {
	return _setupNetworkInterfaces(vmi, domain, NetworkInterface.PlugPhase2)
}

func _setupNetworkInterfaces(vmi *v1.VirtualMachineInstance, domain *api.Domain, plug plugFunction) error {
	// prepare networks map
	networks := map[string]*v1.Network{}
	cniNetworks := map[string]int{}
	for _, network := range vmi.Spec.Networks {
		networks[network.Name] = network.DeepCopy()
		if networks[network.Name].Multus != nil && !networks[network.Name].Multus.Default {
			// multus pod interfaces start from 1
			cniNetworks[network.Name] = len(cniNetworks) + 1
		} else if networks[network.Name].Genie != nil {
			// genie pod interfaces start from 0
			cniNetworks[network.Name] = len(cniNetworks)
		}
	}

	for _, iface := range vmi.Spec.Domain.Devices.Interfaces {
		network, ok := networks[iface.Name]
		if !ok {
			return fmt.Errorf("failed to find a network %s", iface.Name)
		}
		vif, err := NetworkInterfaceFactory(network)
		if err != nil {
			return err
		}

		if networks[iface.Name].Multus != nil && !networks[iface.Name].Multus.Default {
			// multus pod interfaces named netX
			podInterfaceName = fmt.Sprintf("net%d", cniNetworks[iface.Name])
		} else if networks[iface.Name].Genie != nil {
			// genie pod interfaces named ethX
			podInterfaceName = fmt.Sprintf("eth%d", cniNetworks[iface.Name])
		} else {
			podInterfaceName = podInterface
		}

		err = plug(vif, vmi, &iface, network, domain, podInterfaceName)
		if err != nil {
			return err
		}
	}
	return nil
}

// a factory to get suitable network interface
func getNetworkClass(network *v1.Network) (NetworkInterface, error) {
	if network.Pod != nil || network.Multus != nil || network.Genie != nil {
		return new(PodInterface), nil
	}
	return nil, fmt.Errorf("Network not implemented")
}
<commit_msg>Explain why we have 2 net config phases<commit_after>/*
 * This file is part of the KubeVirt project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright 2018 Red Hat, Inc.
 *
 */

package network

//go:generate mockgen -source $GOFILE -package=$GOPACKAGE -destination=generated_mock_$GOFILE

/*
 ATTENTION: Rerun code generators when interface signatures are modified.
*/

import (
	"fmt"

	v1 "kubevirt.io/client-go/api/v1"
	"kubevirt.io/kubevirt/pkg/virt-launcher/virtwrap/api"
)

const podInterface = "eth0"

var interfaceCacheFile = "/var/run/kubevirt/interface-cache-%s-%s.json"
var qemuArgCacheFile = "/var/run/kubevirt/qemu-arg-%s-%s.json"
var vifCacheFile = "/var/run/kubevirt/vif-cache-%s-%s.json"
var NetworkInterfaceFactory = getNetworkClass

var podInterfaceName = podInterface

type plugFunction func(vif NetworkInterface, vmi *v1.VirtualMachineInstance, iface *v1.Interface, network *v1.Network, domain *api.Domain, podInterfaceName string) error

// Network configuration is split into two parts, or phases, each executed in a
// different context. Phase1 is run by virt-handler and heavylifts most
// configuration steps. Phase2 is run by virt-launcher in the pod context and
// completes steps left out of virt-handler. The reason to have a separate phase
// for virt-launcher and not just have all the work done by virt-handler is
// because there is no ready solution for DHCP server startup in virt-handler
// context yet. This is a temporary limitation and the split is expected to go
// once the final gap is closed. Moving all configuration steps into virt-handler
// will also allow to downgrade privileges for virt-launcher, specifically, to
// remove NET_ADMIN capability. Future patches should address that.
type NetworkInterface interface {
	PlugPhase1(vmi *v1.VirtualMachineInstance, iface *v1.Interface, network *v1.Network, domain *api.Domain, podInterfaceName string) error
	PlugPhase2(vmi *v1.VirtualMachineInstance, iface *v1.Interface, network *v1.Network, domain *api.Domain, podInterfaceName string) error
	Unplug()
}

func SetupNetworkInterfacesPhase1(vmi *v1.VirtualMachineInstance, domain *api.Domain) error {
	return _setupNetworkInterfaces(vmi, domain, NetworkInterface.PlugPhase1)
}

func SetupNetworkInterfacesPhase2(vmi *v1.VirtualMachineInstance, domain *api.Domain) error {
	return _setupNetworkInterfaces(vmi, domain, NetworkInterface.PlugPhase2)
}

func _setupNetworkInterfaces(vmi *v1.VirtualMachineInstance, domain *api.Domain, plug plugFunction) error {
	// prepare networks map
	networks := map[string]*v1.Network{}
	cniNetworks := map[string]int{}
	for _, network := range vmi.Spec.Networks {
		networks[network.Name] = network.DeepCopy()
		if networks[network.Name].Multus != nil && !networks[network.Name].Multus.Default {
			// multus pod interfaces start from 1
			cniNetworks[network.Name] = len(cniNetworks) + 1
		} else if networks[network.Name].Genie != nil {
			// genie pod interfaces start from 0
			cniNetworks[network.Name] = len(cniNetworks)
		}
	}

	for _, iface := range vmi.Spec.Domain.Devices.Interfaces {
		network, ok := networks[iface.Name]
		if !ok {
			return fmt.Errorf("failed to find a network %s", iface.Name)
		}
		vif, err := NetworkInterfaceFactory(network)
		if err != nil {
			return err
		}

		if networks[iface.Name].Multus != nil && !networks[iface.Name].Multus.Default {
			// multus pod interfaces named netX
			podInterfaceName = fmt.Sprintf("net%d", cniNetworks[iface.Name])
		} else if networks[iface.Name].Genie != nil {
			// genie pod interfaces named ethX
			podInterfaceName = fmt.Sprintf("eth%d", cniNetworks[iface.Name])
		} else {
			podInterfaceName = podInterface
		}

		err = plug(vif, vmi, &iface, network, domain, podInterfaceName)
		if err != nil {
			return err
		}
	}
	return nil
}

// a factory to get suitable network interface
func getNetworkClass(network *v1.Network) (NetworkInterface, error) {
	if network.Pod != nil || network.Multus != nil || network.Genie != nil {
		return new(PodInterface), nil
	}
	return nil, fmt.Errorf("Network not implemented")
}
<|endoftext|>


<commit_before>package loggenmunger

import (
	"math/rand"
	"regexp"
	"strconv"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
)

// RandomizeString takes a string, looks for the random tokens
// (int, string, and timestamp), and replaces them
func RandomizeString(text string, timeformat string) string {
	log.WithFields(log.Fields{
		"text":       text,
		"timeformat": timeformat,
	}).Debug("Starting String Randomization")

	// Bail if we can't get any randomizers
	goodstring, err := regexp.MatchString(`\$\[[^\]]+\]`, text)
	if err != nil {
		log.WithFields(log.Fields{
			"error_msg": err,
			"text":      text,
			"regex":     `\$\[[^\]]+\]`,
		}).Error("Something broke on parsing the text string with a regular expression")
	}

	//Return original string if 0 randomizers
	if !goodstring {
		log.Debug("Found no random tokens, returning the original string")
		return text
	}

	// Find all randomizing tokens
	re := regexp.MustCompile(`\$\[[^\]]+\]`)
	randos := re.FindAllString(text, -1)
	log.WithFields(log.Fields{
		"num":          len(randos),
		"randomTokens": randos,
	}).Debug("Found random tokens")

	// Create a list of new strings to be inserted where the tokens were
	var newstrings []string
	replacer := strings.NewReplacer("$[", "", "]", "")

	// Append the properly randomized values to the newstrings slice
	for _, rando := range randos {
		// Take off the leading and trailing formatting
		tempstring := replacer.Replace(rando)
		log.WithFields(log.Fields{
			"tempstring": tempstring,
		}).Debug("Removing the formatting from the items")

		// Split the randomizer into individual items
		tempstrings := strings.Split(tempstring, ",")
		log.WithFields(log.Fields{
			"tempstrings": tempstrings,
			"count":       len(tempstrings),
		}).Debug("Splitting the random tokens up")

		// Numeric ranges will only have two items for an upper and lower bound,
		// timestamps have "time" and "stamp", all the rest are string groups
		var randType string
		num0, err := strconv.Atoi(string(tempstrings[0]))
		num1, err2 := strconv.Atoi(string(tempstrings[1]))
		log.WithFields(log.Fields{
			"num":       num0,
			"error_msg": err,
		}).Debug("Parsing entry 0 as a number")
		log.WithFields(log.Fields{
			"num":       num1,
			"error_msg": err2,
		}).Debug("Parsing entry 1 as a number", "num", num1, "error", err2)

		switch {
		case len(tempstrings) == 2 && err == nil && err2 == nil:
			randType = "Number"
		case tempstrings[0] == "time" && tempstrings[1] == "stamp":
			randType = "Timestamp"
		default:
			randType = "Category"
		}

		log.WithFields(log.Fields{
			"type": randType,
		}).Debug("Finished determining token type")

		switch randType {
		case "Category":
			newstrings = append(newstrings, tempstrings[rand.Intn(len(tempstrings))])
		case "Number":
			// Get a random number in the range
			diff := num1 - num0
			log.Debug("Difference from second and first numbers: ", "diff - ", diff)
			tempnum := rand.Intn(diff)
			log.Debug("Random number from zero adjusted spread: ", "rand - ", tempnum)
			log.Debug("Random number adjusted to range and string converted: ", "rand - ", strconv.Itoa(tempnum+num0))
			newstrings = append(newstrings, strconv.Itoa(tempnum+num0))
		case "Timestamp":
			t := time.Now()
			timeformatted, err := formatTimestamp(t, timeformat)
			if err != nil {
				log.WithFields(log.Fields{
					"error_msg": err,
				}).Error("Formatting the timestamp broke")
			}
			newstrings = append(newstrings, timeformatted)
		}
	}

	nonRandomStrings := re.Split(text, -1)
	var newLogLine []string

	for i := 0; i < len(nonRandomStrings); i++ {
		newLogLine = append(newLogLine, nonRandomStrings[i])
		if i != len(nonRandomStrings)-1 {
			newLogLine = append(newLogLine, newstrings[i])
		}
	}

	log.Debug("Randomization complete: ", "newString - ", strings.Join(newLogLine, ""))

	return strings.Join(newLogLine, "")
}

func formatTimestamp(t time.Time, timeformat string) (string, error) {
	log.Debug("Current time: ", "now - ", t)
	var timeformatted string
	switch timeformat {
	case "epoch":
		timeformatted = strconv.FormatInt(t.Unix(), 10)
	case "epochmilli":
		timeformatted = strconv.FormatInt(t.UnixNano()/1000000, 10)
	case "epochnano":
		timeformatted = strconv.FormatInt(t.UnixNano(), 10)
	default:
		timeformatted = t.Format(timeformat)
	}
	log.Debug("Formatted time: ", "now - ", timeformatted)
	return timeformatted, nil
}
<commit_msg>Refactor tokenization selection<commit_after>package loggenmunger

import (
	"errors"
	"math/rand"
	"regexp"
	"strconv"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
)

// RandomizeString takes a string, looks for the random tokens
// (int, string, and timestamp), and replaces them
func RandomizeString(text string, timeformat string) string {
	log.WithFields(log.Fields{
		"text":       text,
		"timeformat": timeformat,
	}).Debug("Starting String Randomization")

	// Bail if we can't get any randomizers
	goodstring, err := regexp.MatchString(`\$\[[^\]]+\]`, text)
	if err != nil {
		log.WithFields(log.Fields{
			"error_msg": err,
			"text":      text,
			"regex":     `\$\[[^\]]+\]`,
		}).Error("Something broke on parsing the text string with a regular expression")
	}

	//Return original string if 0 randomizers
	if !goodstring {
		log.Debug("Found no random tokens, returning the original string")
		return text
	}

	// Find all randomizing tokens
	re := regexp.MustCompile(`\$\[[^\]]+\]`)
	randos := re.FindAllString(text, -1)
	log.WithFields(log.Fields{
		"num":          len(randos),
		"randomTokens": randos,
	}).Debug("Found random tokens")

	// Create a list of new strings to be inserted where the tokens were
	var newstrings []string

	// Append the properly randomized values to the newstrings slice
	for _, rando := range randos {
		value, err := getOneToken(rando, timeformat)
		if err != nil {
			log.WithFields(log.Fields{
				"error":        err,
				"randomTokens": rando,
			}).Warn("Couldn't get value from token list. Using default TOKEN_ERROR")
			value = "TOKEN_ERROR"
		}

		newstrings = append(newstrings, value)
	}

	// We can use the same regex that found the tokens to split up the original string
	// That gives us clear insertion points for our selected tokens
	nonRandomStrings := re.Split(text, -1)
	var newLogLine []string

	for i := 0; i < len(nonRandomStrings); i++ {
		newLogLine = append(newLogLine, nonRandomStrings[i])
		if i != len(nonRandomStrings)-1 {
			newLogLine = append(newLogLine, newstrings[i])
		}
	}

	log.Debug("Randomization complete: ", "newString - ", strings.Join(newLogLine, ""))

	return strings.Join(newLogLine, "")
}

func getOneToken(tokenString string, timeformat string) (string, error) {
	replacer := strings.NewReplacer("$[", "", "]", "")

	// Take off the leading and trailing formatting
	tempstring := replacer.Replace(tokenString)
	log.WithFields(log.Fields{
		"tempstring": tempstring,
	}).Debug("Removing the formatting from the item list")

	// Split the randomizer into individual items
	itemList := strings.Split(tempstring, ",")
	log.WithFields(log.Fields{
		"itemList": itemList,
		"count":    len(itemList),
	}).Debug("Splitting the random tokens up")

	// Numeric ranges will only have two items for an upper and lower bound,
	// timestamps have "time" and "stamp", all the rest are string groups
	var randType string
	num0, err := strconv.Atoi(string(itemList[0]))
	num1, err2 := strconv.Atoi(string(itemList[1]))
	log.WithFields(log.Fields{
		"num":       num0,
		"error_msg": err,
	}).Debug("Parsing entry 0 as a number")
	log.WithFields(log.Fields{
		"num":       num1,
		"error_msg": err2,
	}).Debug("Parsing entry 1 as a number")

	// Set the logic for categorization here, so it's not buried in the switch
	switch {
	case len(itemList) == 2 && err == nil && err2 == nil:
		randType = "Number"
	case itemList[0] == "time" && itemList[1] == "stamp":
		randType = "Timestamp"
	default:
		randType = "Category"
	}

	log.WithFields(log.Fields{
		"type": randType,
	}).Debug("Finished determining token type")

	switch randType {
	case "Category":
		return itemList[rand.Intn(len(itemList))], nil
	case "Number":
		// Get a random number in the range
		diff := num1 - num0
		log.Debug("Difference from second and first numbers: ", "diff - ", diff)
		tempnum := rand.Intn(diff)
		log.Debug("Random number from zero adjusted spread: ", "rand - ", tempnum)
		log.Debug("Random number adjusted to range and string converted: ", "rand - ", strconv.Itoa(tempnum+num0))
		return strconv.Itoa(tempnum + num0), nil
	case "Timestamp":
		t := time.Now()
		timeformatted, err := formatTimestamp(t, timeformat)
		if err != nil {
			log.WithFields(log.Fields{
				"error_msg": err,
			}).Error("Formatting the timestamp broke")
		}
		return timeformatted, nil
	}

	// Failure case. Should never happen.
	return "", errors.New("Unknown error trying to get a token from the list: " + tokenString)
}

func formatTimestamp(t time.Time, timeformat string) (string, error) {
	log.Debug("Current time: ", "now - ", t)
	var timeformatted string
	switch timeformat {
	case "epoch":
		timeformatted = strconv.FormatInt(t.Unix(), 10)
	case "epochmilli":
		timeformatted = strconv.FormatInt(t.UnixNano()/1000000, 10)
	case "epochnano":
		timeformatted = strconv.FormatInt(t.UnixNano(), 10)
	default:
		timeformatted = t.Format(timeformat)
	}
	log.Debug("Formatted time: ", "now - ", timeformatted)
	return timeformatted, nil
}
<|endoftext|>


<commit_before>package framework

import (
	"fmt"
	"io/ioutil"
	"log"
	"regexp"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/hashicorp/go-multierror"
	"github.com/hashicorp/vault/logical"
)

// Backend is an implementation of logical.Backend that allows
// the implementer to code a backend using a much more programmer-friendly
// framework that handles a lot of the routing and validation for you.
//
// This is recommended over implementing logical.Backend directly.
type Backend struct {
	// Help is the help text that is shown when a help request is made
	// on the root of this resource. The root help is special since we
	// show all the paths that can be requested.
	Help string

	// Paths are the various routes that the backend responds to.
	// This cannot be modified after construction (i.e. dynamically changing
	// paths, including adding or removing, is not allowed once the
	// backend is in use).
	//
	// PathsSpecial is the list of path patterns that denote the
	// paths above that require special privileges. These can't be
	// regular expressions, it is either exact match or prefix match.
	// For prefix match, append '*' as a suffix.
	Paths        []*Path
	PathsSpecial *logical.Paths

	// Secrets is the list of secret types that this backend can
	// return. It is used to automatically generate proper responses,
	// and ease specifying callbacks for revocation, renewal, etc.
	Secrets []*Secret

	// Rollback is called when a WAL entry (see wal.go) has to be rolled
	// back. It is called with the data from the entry.
	//
	// RollbackMinAge is the minimum age of a WAL entry before it is attempted
	// to be rolled back. This should be longer than the maximum time it takes
	// to successfully create a secret.
	Rollback       RollbackFunc
	RollbackMinAge time.Duration

	// Clean is called on unload to clean up e.g any existing connections
	// to the backend, if required.
	Clean CleanupFunc

	// AuthRenew is the callback to call when a RenewRequest for an
	// authentication comes in. By default, renewal won't be allowed.
	// See the built-in AuthRenew helpers in lease.go for common callbacks.
	AuthRenew OperationFunc

	logger  *log.Logger
	system  logical.SystemView
	once    sync.Once
	pathsRe []*regexp.Regexp
}

// OperationFunc is the callback called for an operation on a path.
type OperationFunc func(*logical.Request, *FieldData) (*logical.Response, error)

// RollbackFunc is the callback for rollbacks.
type RollbackFunc func(*logical.Request, string, interface{}) error

// CleanupFunc is the callback for backend unload.
type CleanupFunc func()

// logical.Backend impl.
func (b *Backend) HandleRequest(req *logical.Request) (*logical.Response, error) {
	b.once.Do(b.init)

	// Check for special cased global operations. These don't route
	// to a specific Path.
	switch req.Operation {
	case logical.RenewOperation:
		fallthrough
	case logical.RevokeOperation:
		return b.handleRevokeRenew(req)
	case logical.RollbackOperation:
		return b.handleRollback(req)
	}

	// If the path is empty and it is a help operation, handle that.
	if req.Path == "" && req.Operation == logical.HelpOperation {
		return b.handleRootHelp()
	}

	// Find the matching route
	path, captures := b.route(req.Path)
	if path == nil {
		return nil, logical.ErrUnsupportedPath
	}

	// Build up the data for the route, with the URL taking priority
	// for the fields over the PUT data.
	raw := make(map[string]interface{}, len(path.Fields))
	for k, v := range req.Data {
		raw[k] = v
	}
	for k, v := range captures {
		raw[k] = v
	}

	// Look up the callback for this operation
	var callback OperationFunc
	var ok bool
	if path.Callbacks != nil {
		callback, ok = path.Callbacks[req.Operation]
	}
	if !ok {
		if req.Operation == logical.HelpOperation {
			callback = path.helpCallback
			ok = true
		}
	}
	if !ok {
		return nil, logical.ErrUnsupportedOperation
	}

	fd := FieldData{
		Raw:    raw,
		Schema: path.Fields}

	if req.Operation != logical.HelpOperation {
		err := fd.Validate()
		if err != nil {
			return nil, err
		}
	}

	// Call the callback with the request and the data
	return callback(req, &fd)
}

// logical.Backend impl.
func (b *Backend) SpecialPaths() *logical.Paths {
	return b.PathsSpecial
}

// Setup is used to initialize the backend with the initial backend configuration
func (b *Backend) Setup(config *logical.BackendConfig) (logical.Backend, error) {
	b.logger = config.Logger
	b.system = config.System
	return b, nil
}

func (b *Backend) Cleanup() {
	if b.Clean != nil {
		b.Clean()
	}
}

// Logger can be used to get the logger. If no logger has been set,
// the logs will be discarded.
func (b *Backend) Logger() *log.Logger {
	if b.logger != nil {
		return b.logger
	}

	return log.New(ioutil.Discard, "", 0)
}

func (b *Backend) System() logical.SystemView {
	return b.system
}

// This method takes in the TTL and MaxTTL values provided by the user, compares
// those with the SystemView values. If they are empty default values are set.
// If they are set, their boundaries are validated.
func (b *Backend) SanitizeTTL(ttlStr, maxTTLStr string) (ttl, maxTTL time.Duration, err error) {
	if len(ttlStr) == 0 {
		ttl = b.System().DefaultLeaseTTL()
	} else {
		ttl, err = time.ParseDuration(ttlStr)
		if err != nil {
			return 0, 0, fmt.Errorf("Invalid ttl: %s", err)
		}
	}
	sysMaxTTL := b.System().MaxLeaseTTL()
	if len(maxTTLStr) == 0 {
		maxTTL = sysMaxTTL
	} else {
		maxTTL, err = time.ParseDuration(maxTTLStr)
		if err != nil {
			return 0, 0, fmt.Errorf("Invalid max_ttl: %s", err)
		}
	}
	if maxTTL > sysMaxTTL {
		maxTTL = sysMaxTTL
	}
	if ttl > maxTTL {
		ttl = maxTTL
	}
	return
}

// Route looks up the path that would be used for a given path string.
func (b *Backend) Route(path string) *Path {
	result, _ := b.route(path)
	return result
}

// Secret is used to look up the secret with the given type.
func (b *Backend) Secret(k string) *Secret {
	for _, s := range b.Secrets {
		if s.Type == k {
			return s
		}
	}

	return nil
}

func (b *Backend) init() {
	b.pathsRe = make([]*regexp.Regexp, len(b.Paths))
	for i, p := range b.Paths {
		if len(p.Pattern) == 0 {
			panic(fmt.Sprintf("Routing pattern cannot be blank"))
		}
		// Automatically anchor the pattern
		if p.Pattern[0] != '^' {
			p.Pattern = "^" + p.Pattern
		}
		if p.Pattern[len(p.Pattern)-1] != '$' {
			p.Pattern = p.Pattern + "$"
		}
		b.pathsRe[i] = regexp.MustCompile(p.Pattern)
	}
}

func (b *Backend) route(path string) (*Path, map[string]string) {
	b.once.Do(b.init)

	for i, re := range b.pathsRe {
		matches := re.FindStringSubmatch(path)
		if matches == nil {
			continue
		}

		// We have a match, determine the mapping of the captures and
		// store that for returning.
		var captures map[string]string
		path := b.Paths[i]
		if captureNames := re.SubexpNames(); len(captureNames) > 1 {
			captures = make(map[string]string, len(captureNames))
			for i, name := range captureNames {
				if name != "" {
					captures[name] = matches[i]
				}
			}
		}

		return path, captures
	}

	return nil, nil
}

func (b *Backend) handleRootHelp() (*logical.Response, error) {
	// Build a mapping of the paths and get the paths alphabetized to
	// make the output prettier.
	pathsMap := make(map[string]*Path)
	paths := make([]string, 0, len(b.Paths))
	for i, p := range b.pathsRe {
		paths = append(paths, p.String())
		pathsMap[p.String()] = b.Paths[i]
	}
	sort.Strings(paths)

	// Build the path data
	pathData := make([]rootHelpTemplatePath, 0, len(paths))
	for _, route := range paths {
		p := pathsMap[route]
		pathData = append(pathData, rootHelpTemplatePath{
			Path: route,
			Help: strings.TrimSpace(p.HelpSynopsis),
		})
	}

	help, err := executeTemplate(rootHelpTemplate, &rootHelpTemplateData{
		Help:  strings.TrimSpace(b.Help),
		Paths: pathData,
	})
	if err != nil {
		return nil, err
	}

	return logical.HelpResponse(help, nil), nil
}

func (b *Backend) handleRevokeRenew(
	req *logical.Request) (*logical.Response, error) {
	// Special case renewal of authentication for credential backends
	if req.Operation == logical.RenewOperation && req.Auth != nil {
		return b.handleAuthRenew(req)
	}

	if req.Secret == nil {
		return nil, fmt.Errorf("request has no secret")
	}

	rawSecretType, ok := req.Secret.InternalData["secret_type"]
	if !ok {
		return nil, fmt.Errorf("secret is unsupported by this backend")
	}
	secretType, ok := rawSecretType.(string)
	if !ok {
		return nil, fmt.Errorf("secret is unsupported by this backend")
	}

	secret := b.Secret(secretType)
	if secret == nil {
		return nil, fmt.Errorf("secret is unsupported by this backend")
	}

	switch req.Operation {
	case logical.RenewOperation:
		return secret.HandleRenew(req)
	case logical.RevokeOperation:
		return secret.HandleRevoke(req)
	default:
		return nil, fmt.Errorf(
			"invalid operation for revoke/renew: %s", req.Operation)
	}
}

func (b *Backend) handleAuthRenew(req *logical.Request) (*logical.Response, error) {
	if b.AuthRenew == nil {
		return logical.ErrorResponse("this auth type doesn't support renew"), nil
	}

	return b.AuthRenew(req, nil)
}

func (b *Backend) handleRollback(
	req *logical.Request) (*logical.Response, error) {
	if b.Rollback == nil {
		return nil, logical.ErrUnsupportedOperation
	}

	var merr error
	keys, err := ListWAL(req.Storage)
	if err != nil {
		return logical.ErrorResponse(err.Error()), nil
	}
	if len(keys) == 0 {
		return nil, nil
	}

	// Calculate the minimum time that the WAL entries could be
	// created in order to be rolled back.
	age := b.RollbackMinAge
	if age == 0 {
		age = 10 * time.Minute
	}
	minAge := time.Now().UTC().Add(-1 * age)
	if _, ok := req.Data["immediate"]; ok {
		minAge = time.Now().UTC().Add(1000 * time.Hour)
	}

	for _, k := range keys {
		entry, err := GetWAL(req.Storage, k)
		if err != nil {
			merr = multierror.Append(merr, err)
			continue
		}
		if entry == nil {
			continue
		}

		// If the entry isn't old enough, then don't roll it back
		if !time.Unix(entry.CreatedAt, 0).Before(minAge) {
			continue
		}

		// Attempt a rollback
		err = b.Rollback(req, entry.Kind, entry.Data)
		if err != nil {
			err = fmt.Errorf(
				"Error rolling back '%s' entry: %s", entry.Kind, err)
		}
		if err == nil {
			err = DeleteWAL(req.Storage, k)
		}
		if err != nil {
			merr = multierror.Append(merr, err)
		}
	}

	if merr == nil {
		return nil, nil
	}

	return logical.ErrorResponse(merr.Error()), nil
}

// FieldSchema is a basic schema to describe the format of a path field.
type FieldSchema struct {
	Type        FieldType
	Default     interface{}
	Description string
}

// DefaultOrZero returns the default value if it is set, or otherwise
// the zero value of the type.
func (s *FieldSchema) DefaultOrZero() interface{} {
	if s.Default != nil {
		return s.Default
	}

	return s.Type.Zero()
}

func (t FieldType) Zero() interface{} {
	switch t {
	case TypeString:
		return ""
	case TypeInt:
		return 0
	case TypeBool:
		return false
	case TypeMap:
		return map[string]interface{}{}
	case TypeDurationSecond:
		return 0
	default:
		panic("unknown type: " + t.String())
	}
}

type rootHelpTemplateData struct {
	Help  string
	Paths []rootHelpTemplatePath
}

type rootHelpTemplatePath struct {
	Path string
	Help string
}

const rootHelpTemplate = `
## DESCRIPTION

{{.Help}}

## PATHS

The following paths are supported by this backend. To view help for
any of the paths below, use the help command with any route matching
the path pattern. Note that depending on the policy of your auth token,
you may or may not be able to access certain paths.

{{range .Paths}}{{indent 4 .Path}}
{{indent 8 .Help}}

{{end}}

`
<commit_msg>Error on violating SysView boundaries<commit_after>package framework

import (
	"fmt"
	"io/ioutil"
	"log"
	"regexp"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/hashicorp/go-multierror"
	"github.com/hashicorp/vault/logical"
)

// Backend is an implementation of logical.Backend that allows
// the implementer to code a backend using a much more programmer-friendly
// framework that handles a lot of the routing and validation for you.
//
// This is recommended over implementing logical.Backend directly.
type Backend struct {
	// Help is the help text that is shown when a help request is made
	// on the root of this resource. The root help is special since we
	// show all the paths that can be requested.
	Help string

	// Paths are the various routes that the backend responds to.
	// This cannot be modified after construction (i.e. dynamically changing
	// paths, including adding or removing, is not allowed once the
	// backend is in use).
	//
	// PathsSpecial is the list of path patterns that denote the
	// paths above that require special privileges. These can't be
	// regular expressions, it is either exact match or prefix match.
	// For prefix match, append '*' as a suffix.
	Paths        []*Path
	PathsSpecial *logical.Paths

	// Secrets is the list of secret types that this backend can
	// return. It is used to automatically generate proper responses,
	// and ease specifying callbacks for revocation, renewal, etc.
	Secrets []*Secret

	// Rollback is called when a WAL entry (see wal.go) has to be rolled
	// back. It is called with the data from the entry.
	//
	// RollbackMinAge is the minimum age of a WAL entry before it is attempted
	// to be rolled back. This should be longer than the maximum time it takes
	// to successfully create a secret.
	Rollback       RollbackFunc
	RollbackMinAge time.Duration

	// Clean is called on unload to clean up e.g any existing connections
	// to the backend, if required.
	Clean CleanupFunc

	// AuthRenew is the callback to call when a RenewRequest for an
	// authentication comes in. By default, renewal won't be allowed.
	// See the built-in AuthRenew helpers in lease.go for common callbacks.
	AuthRenew OperationFunc

	logger  *log.Logger
	system  logical.SystemView
	once    sync.Once
	pathsRe []*regexp.Regexp
}

// OperationFunc is the callback called for an operation on a path.
type OperationFunc func(*logical.Request, *FieldData) (*logical.Response, error)

// RollbackFunc is the callback for rollbacks.
type RollbackFunc func(*logical.Request, string, interface{}) error

// CleanupFunc is the callback for backend unload.
type CleanupFunc func()

// logical.Backend impl.
func (b *Backend) HandleRequest(req *logical.Request) (*logical.Response, error) {
	b.once.Do(b.init)

	// Check for special cased global operations. These don't route
	// to a specific Path.
	switch req.Operation {
	case logical.RenewOperation:
		fallthrough
	case logical.RevokeOperation:
		return b.handleRevokeRenew(req)
	case logical.RollbackOperation:
		return b.handleRollback(req)
	}

	// If the path is empty and it is a help operation, handle that.
	if req.Path == "" && req.Operation == logical.HelpOperation {
		return b.handleRootHelp()
	}

	// Find the matching route
	path, captures := b.route(req.Path)
	if path == nil {
		return nil, logical.ErrUnsupportedPath
	}

	// Build up the data for the route, with the URL taking priority
	// for the fields over the PUT data.
	raw := make(map[string]interface{}, len(path.Fields))
	for k, v := range req.Data {
		raw[k] = v
	}
	for k, v := range captures {
		raw[k] = v
	}

	// Look up the callback for this operation
	var callback OperationFunc
	var ok bool
	if path.Callbacks != nil {
		callback, ok = path.Callbacks[req.Operation]
	}
	if !ok {
		if req.Operation == logical.HelpOperation {
			callback = path.helpCallback
			ok = true
		}
	}
	if !ok {
		return nil, logical.ErrUnsupportedOperation
	}

	fd := FieldData{
		Raw:    raw,
		Schema: path.Fields}

	if req.Operation != logical.HelpOperation {
		err := fd.Validate()
		if err != nil {
			return nil, err
		}
	}

	// Call the callback with the request and the data
	return callback(req, &fd)
}

// logical.Backend impl.
func (b *Backend) SpecialPaths() *logical.Paths {
	return b.PathsSpecial
}

// Setup is used to initialize the backend with the initial backend configuration
func (b *Backend) Setup(config *logical.BackendConfig) (logical.Backend, error) {
	b.logger = config.Logger
	b.system = config.System
	return b, nil
}

func (b *Backend) Cleanup() {
	if b.Clean != nil {
		b.Clean()
	}
}

// Logger can be used to get the logger. If no logger has been set,
// the logs will be discarded.
func (b *Backend) Logger() *log.Logger {
	if b.logger != nil {
		return b.logger
	}

	return log.New(ioutil.Discard, "", 0)
}

func (b *Backend) System() logical.SystemView {
	return b.system
}

// This method takes in the TTL and MaxTTL values provided by the user, compares
// those with the SystemView values. If they are empty default values are set.
// If they are set, their boundaries are validated.
func (b *Backend) SanitizeTTL(ttlStr, maxTTLStr string) (ttl, maxTTL time.Duration, err error) {
	sysMaxTTL := b.System().MaxLeaseTTL()
	if len(ttlStr) == 0 {
		ttl = b.System().DefaultLeaseTTL()
	} else {
		ttl, err = time.ParseDuration(ttlStr)
		if err != nil {
			return 0, 0, fmt.Errorf("Invalid ttl: %s", err)
		}
		if ttl > sysMaxTTL {
			return 0, 0, fmt.Errorf("\"ttl\" value must be less than allowed max lease TTL value '%s'", sysMaxTTL.String())
		}
	}
	if len(maxTTLStr) == 0 {
		maxTTL = sysMaxTTL
	} else {
		maxTTL, err = time.ParseDuration(maxTTLStr)
		if err != nil {
			return 0, 0, fmt.Errorf("Invalid max_ttl: %s", err)
		}
		if maxTTL > sysMaxTTL {
			return 0, 0, fmt.Errorf("\"max_ttl\" value must be less than allowed max lease TTL value '%s'", sysMaxTTL.String())
		}
	}
	if ttl > maxTTL {
		ttl = maxTTL
	}
	return
}

// Route looks up the path that would be used for a given path string.
func (b *Backend) Route(path string) *Path {
	result, _ := b.route(path)
	return result
}

// Secret is used to look up the secret with the given type.
func (b *Backend) Secret(k string) *Secret {
	for _, s := range b.Secrets {
		if s.Type == k {
			return s
		}
	}

	return nil
}

func (b *Backend) init() {
	b.pathsRe = make([]*regexp.Regexp, len(b.Paths))
	for i, p := range b.Paths {
		if len(p.Pattern) == 0 {
			panic(fmt.Sprintf("Routing pattern cannot be blank"))
		}
		// Automatically anchor the pattern
		if p.Pattern[0] != '^' {
			p.Pattern = "^" + p.Pattern
		}
		if p.Pattern[len(p.Pattern)-1] != '$' {
			p.Pattern = p.Pattern + "$"
		}
		b.pathsRe[i] = regexp.MustCompile(p.Pattern)
	}
}

func (b *Backend) route(path string) (*Path, map[string]string) {
	b.once.Do(b.init)

	for i, re := range b.pathsRe {
		matches := re.FindStringSubmatch(path)
		if matches == nil {
			continue
		}

		// We have a match, determine the mapping of the captures and
		// store that for returning.
		var captures map[string]string
		path := b.Paths[i]
		if captureNames := re.SubexpNames(); len(captureNames) > 1 {
			captures = make(map[string]string, len(captureNames))
			for i, name := range captureNames {
				if name != "" {
					captures[name] = matches[i]
				}
			}
		}

		return path, captures
	}

	return nil, nil
}

func (b *Backend) handleRootHelp() (*logical.Response, error) {
	// Build a mapping of the paths and get the paths alphabetized to
	// make the output prettier.
	pathsMap := make(map[string]*Path)
	paths := make([]string, 0, len(b.Paths))
	for i, p := range b.pathsRe {
		paths = append(paths, p.String())
		pathsMap[p.String()] = b.Paths[i]
	}
	sort.Strings(paths)

	// Build the path data
	pathData := make([]rootHelpTemplatePath, 0, len(paths))
	for _, route := range paths {
		p := pathsMap[route]
		pathData = append(pathData, rootHelpTemplatePath{
			Path: route,
			Help: strings.TrimSpace(p.HelpSynopsis),
		})
	}

	help, err := executeTemplate(rootHelpTemplate, &rootHelpTemplateData{
		Help:  strings.TrimSpace(b.Help),
		Paths: pathData,
	})
	if err != nil {
		return nil, err
	}

	return logical.HelpResponse(help, nil), nil
}

func (b *Backend) handleRevokeRenew(
	req *logical.Request) (*logical.Response, error) {
	// Special case renewal of authentication for credential backends
	if req.Operation == logical.RenewOperation && req.Auth != nil {
		return b.handleAuthRenew(req)
	}

	if req.Secret == nil {
		return nil, fmt.Errorf("request has no secret")
	}

	rawSecretType, ok := req.Secret.InternalData["secret_type"]
	if !ok {
		return nil, fmt.Errorf("secret is unsupported by this backend")
	}
	secretType, ok := rawSecretType.(string)
	if !ok {
		return nil, fmt.Errorf("secret is unsupported by this backend")
	}

	secret := b.Secret(secretType)
	if secret == nil {
		return nil, fmt.Errorf("secret is unsupported by this backend")
	}

	switch req.Operation {
	case logical.RenewOperation:
		return secret.HandleRenew(req)
	case logical.RevokeOperation:
		return secret.HandleRevoke(req)
	default:
		return nil, fmt.Errorf(
			"invalid operation for revoke/renew: %s", req.Operation)
	}
}

func (b *Backend) handleAuthRenew(req *logical.Request) (*logical.Response, error) {
	if b.AuthRenew == nil {
		return logical.ErrorResponse("this auth type doesn't support renew"), nil
	}

	return b.AuthRenew(req, nil)
}

func (b *Backend) handleRollback(
	req *logical.Request) (*logical.Response, error) {
	if b.Rollback == nil {
		return nil, logical.ErrUnsupportedOperation
	}

	var merr error
	keys, err := ListWAL(req.Storage)
	if err != nil {
		return logical.ErrorResponse(err.Error()), nil
	}
	if len(keys) == 0 {
		return nil, nil
	}

	// Calculate the minimum time that the WAL entries could be
	// created in order to be rolled back.
	age := b.RollbackMinAge
	if age == 0 {
		age = 10 * time.Minute
	}
	minAge := time.Now().UTC().Add(-1 * age)
	if _, ok := req.Data["immediate"]; ok {
		minAge = time.Now().UTC().Add(1000 * time.Hour)
	}

	for _, k := range keys {
		entry, err := GetWAL(req.Storage, k)
		if err != nil {
			merr = multierror.Append(merr, err)
			continue
		}
		if entry == nil {
			continue
		}

		// If the entry isn't old enough, then don't roll it back
		if !time.Unix(entry.CreatedAt, 0).Before(minAge) {
			continue
		}

		// Attempt a rollback
		err = b.Rollback(req, entry.Kind, entry.Data)
		if err != nil {
			err = fmt.Errorf(
				"Error rolling back '%s' entry: %s", entry.Kind, err)
		}
		if err == nil {
			err = DeleteWAL(req.Storage, k)
		}
		if err != nil {
			merr = multierror.Append(merr, err)
		}
	}

	if merr == nil {
		return nil, nil
	}

	return logical.ErrorResponse(merr.Error()), nil
}

// FieldSchema is a basic schema to describe the format of a path field.
type FieldSchema struct {
	Type        FieldType
	Default     interface{}
	Description string
}

// DefaultOrZero returns the default value if it is set, or otherwise
// the zero value of the type.
func (s *FieldSchema) DefaultOrZero() interface{} {
	if s.Default != nil {
		return s.Default
	}

	return s.Type.Zero()
}

func (t FieldType) Zero() interface{} {
	switch t {
	case TypeString:
		return ""
	case TypeInt:
		return 0
	case TypeBool:
		return false
	case TypeMap:
		return map[string]interface{}{}
	case TypeDurationSecond:
		return 0
	default:
		panic("unknown type: " + t.String())
	}
}

type rootHelpTemplateData struct {
	Help  string
	Paths []rootHelpTemplatePath
}

type rootHelpTemplatePath struct {
	Path string
	Help string
}

const rootHelpTemplate = `
## DESCRIPTION

{{.Help}}

## PATHS

The following paths are supported by this backend. To view help for
any of the paths below, use the help command with any route matching
the path pattern. Note that depending on the policy of your auth token,
you may or may not be able to access certain paths.

{{range .Paths}}{{indent 4 .Path}}
{{indent 8 .Help}}

{{end}}

`
<|endoftext|>


<commit_before>package jsonselect

import (
    "errors"
    "fmt"
    "regexp"
    "strings"
    "strconv"
)

type tokenType string

type token struct {
    typ tokenType
    val interface{}
}

type scannerItem struct {
    regex *regexp.Regexp
    typ tokenType
}

const (
    S_TYPE tokenType = "type"
    S_IDENTIFIER tokenType = "identifier"
    S_QUOTED_IDENTIFIER tokenType = "quoted_identifier"
    S_PCLASS tokenType = "pclass"
    S_PCLASS_FUNC tokenType = "pclass_func"
    S_NTH_FUNC tokenType = "nth_func"
    S_OPER tokenType = "operator"
    S_EMPTY tokenType = "empty"
    S_UNK tokenType = "unknown"
    S_FLOAT tokenType = "float"
    S_WORD tokenType = "word"
    S_BINOP tokenType = "binop"
    S_BOOL tokenType = "bool"
    S_NIL tokenType = "null"
    S_KEYWORD tokenType = "keyword"
    S_PVAR tokenType = "pvar"
    S_EXPR tokenType = "expr"
    S_NUMBER tokenType = "number"
    S_STRING tokenType = "string"
    S_PAREN tokenType = "paren"
)

var SCANNER = []scannerItem{
    scannerItem{
        regexp.MustCompile(`\([^\)]+\)`),
        S_EXPR,
    },
    scannerItem{
        regexp.MustCompile(`[~*,> ]`),
        S_OPER,
    },
    scannerItem{
        regexp.MustCompile(`\s`),
        S_EMPTY,
    },
    scannerItem{
        regexp.MustCompile(`(-?\d+(\.\d*)([eE][+\-]?\d+)?)`),
        S_FLOAT,
    },
    scannerItem{
        regexp.MustCompile(`string|boolean|null|array|object|number`),
        S_TYPE,
    },
    scannerItem{
        regexp.MustCompile(`\"([_a-zA-Z]|\\[^\s0-9a-fA-F])([_a-zA-Z0-9\-]|(\\[^\s0-9a-fA-F]))*\"`),
        S_WORD,
    },
    scannerItem{
        regexp.MustCompile(`\.?\"([^"\\]|\\[^"])*\"`),
        S_QUOTED_IDENTIFIER,
    },
    scannerItem{
        regexp.MustCompile(`\.([_a-zA-Z]|\\[^\s0-9a-fA-F])([_a-zA-Z0-9\-]|(\\[^\s0-9a-fA-F]))*`),
        S_IDENTIFIER,
    },
    scannerItem{
        regexp.MustCompile(`:(root|empty|first-child|last-child|only-child)`),
        S_PCLASS,
    },
    scannerItem{
        regexp.MustCompile(`:(has|expr|val|contains)`),
        S_PCLASS_FUNC,
    },
    scannerItem{
        regexp.MustCompile(`:(nth-child|nth-last-child)`),
        S_NTH_FUNC,
    },
    scannerItem{
        regexp.MustCompile(`(&&|\|\||[\$\^<>!\*]=|[=+\-*/%<>])`),
        S_BINOP,
    },
    scannerItem{
        regexp.MustCompile(`true|false`),
        S_BOOL,
    },
    scannerItem{
        regexp.MustCompile(`null`),
        S_NIL,
    },
    scannerItem{
        regexp.MustCompile(`n`),
        S_PVAR,
    },
    scannerItem{
        regexp.MustCompile(`odd|even`),
        S_KEYWORD,
    },
}

var EXPRESSION_SCANNER = []scannerItem{
    scannerItem{
        regexp.MustCompile(`\s`),
        S_KEYWORD,
    },
    scannerItem{
        regexp.MustCompile(`true`),
        S_BOOL,
    },
    scannerItem{
        regexp.MustCompile(`null`),
        S_NIL,
    },
    scannerItem{
        regexp.MustCompile(`-?\d+(\.\d*)?([eE][+\-]?\d+)?`),
        S_NUMBER,
    },
    scannerItem{
        regexp.MustCompile(`\"([^\]|\[^\"])*\"`),
        S_STRING,
    },
    scannerItem{
        regexp.MustCompile(`x`),
        S_PVAR,
    },
    scannerItem{
        regexp.MustCompile(`(&&|\|\||[\$\^<>!\*]=|[=+\-*/%<>])`),
        S_BINOP,
    },
    scannerItem{
        regexp.MustCompile(`\(|\)`),
        S_PAREN,
    },
}

func lexNextToken(input string, scanners []scannerItem) (*token, int, error) {
    for _, scanner := range scanners {
        idx := scanner.regex.FindStringIndex(input)
        if idx == nil {
            continue
        }
        if idx[0] == 0 {
            if scanner.typ == S_EXPR && strings.Count(input[idx[0]:idx[1]], "(") != strings.Count(input[idx[0]:idx[1]], ")") {
                terminated := false
                var curr int
                for curr = idx[1]; curr <= len(input[idx[0]:]); curr++ {
                    if strings.Count(input[idx[0]:curr], "(") == strings.Count(input[idx[0]:curr], ")") {
                        terminated = true
                        break
                    }
                }
                if terminated == false {
                    return nil, len(input), errors.New(fmt.Sprintf("Unterminated expression: %s", input[idx[0]:curr-1]))
                } else {
                    idx[1] = curr
                }
            }
            token := getToken(
                scanner.typ,
                input[idx[0]:idx[1]],
            )
            return &token, idx[1], nil
        }
    }
    return nil, len(input), errors.New(fmt.Sprintf("Parsing error at %s", input))
}

func Lex(input string, scanners []scannerItem) ([]*token, error) {
    var tokens []*token
    var start = 0
    for start < len(input) {
        token, new_value, err := lexNextToken(input[start:], scanners)
        if err != nil {
            return nil, err
        }
        start = start + new_value
        if token.typ != S_EMPTY {
            tokens = append(
                tokens,
                token,
            )
        }
    }
    logger.Print("Tokenization results: ", input)
    for i, token := range tokens {
        logger.Print("[", i, "] ", token)
    }
    return tokens, nil
}

func getToken(typ tokenType, val string) token {
    switch typ {
        case S_IDENTIFIER, S_PCLASS, S_PCLASS_FUNC, S_NTH_FUNC:
            return token{typ, val[1:]}
        case S_QUOTED_IDENTIFIER:
            return token{S_IDENTIFIER, val[2:len(val)-1]}
        case S_NIL:
            return token{typ, nil}
        case S_BOOL:
            result, _ := strconv.ParseBool(val)
            return token{typ, result}
        case S_NUMBER:
            result, _ := strconv.ParseInt(val, 10, 64)
            return token{typ, result}
        case S_EMPTY:
            return token{typ, " "}
        case S_FLOAT:
            result, _ := strconv.ParseFloat(val, 32)
            return token{typ, result}
        case S_WORD:
            return token{typ, val[1:len(val)-1]}
        default:
            return token{typ, val}
    }
}
<commit_msg>Fixing operators; level one and two tests now pass.<commit_after>package jsonselect

import (
    "errors"
    "fmt"
    "regexp"
    "strings"
    "strconv"
)

type tokenType string

type token struct {
    typ tokenType
    val interface{}
}

type scannerItem struct {
    regex *regexp.Regexp
    typ tokenType
}

const (
    S_TYPE tokenType = "type"
    S_IDENTIFIER tokenType = "identifier"
    S_QUOTED_IDENTIFIER tokenType = "quoted_identifier"
    S_PCLASS tokenType = "pclass"
    S_PCLASS_FUNC tokenType = "pclass_func"
    S_NTH_FUNC tokenType = "nth_func"
    S_OPER tokenType = "operator"
    S_EMPTY tokenType = "empty"
    S_UNK tokenType = "unknown"
    S_FLOAT tokenType = "float"
    S_WORD tokenType = "word"
    S_BINOP tokenType = "binop"
    S_BOOL tokenType = "bool"
    S_NIL tokenType = "null"
    S_KEYWORD tokenType = "keyword"
    S_PVAR tokenType = "pvar"
    S_EXPR tokenType = "expr"
    S_NUMBER tokenType = "number"
    S_STRING tokenType = "string"
    S_PAREN tokenType = "paren"
)

var SCANNER = []scannerItem{
    scannerItem{
        regexp.MustCompile(`\([^\)]+\)`),
        S_EXPR,
    },
    scannerItem{
        regexp.MustCompile(`[~*,>]`),
        S_OPER,
    },
    scannerItem{
        regexp.MustCompile(`\s`),
        S_EMPTY,
    },
    scannerItem{
        regexp.MustCompile(`(-?\d+(\.\d*)([eE][+\-]?\d+)?)`),
        S_FLOAT,
    },
    scannerItem{
        regexp.MustCompile(`string|boolean|null|array|object|number`),
        S_TYPE,
    },
    scannerItem{
        regexp.MustCompile(`\"([_a-zA-Z]|\\[^\s0-9a-fA-F])([_a-zA-Z0-9\-]|(\\[^\s0-9a-fA-F]))*\"`),
        S_WORD,
    },
    scannerItem{
        regexp.MustCompile(`\.?\"([^"\\]|\\[^"])*\"`),
        S_QUOTED_IDENTIFIER,
    },
    scannerItem{
        regexp.MustCompile(`\.([_a-zA-Z]|\\[^\s0-9a-fA-F])([_a-zA-Z0-9\-]|(\\[^\s0-9a-fA-F]))*`),
        S_IDENTIFIER,
    },
    scannerItem{
        regexp.MustCompile(`:(root|empty|first-child|last-child|only-child)`),
        S_PCLASS,
    },
    scannerItem{
        regexp.MustCompile(`:(has|expr|val|contains)`),
        S_PCLASS_FUNC,
    },
    scannerItem{
        regexp.MustCompile(`:(nth-child|nth-last-child)`),
        S_NTH_FUNC,
    },
    scannerItem{
        regexp.MustCompile(`(&&|\|\||[\$\^<>!\*]=|[=+\-*/%<>])`),
        S_BINOP,
    },
    scannerItem{
        regexp.MustCompile(`true|false`),
        S_BOOL,
    },
    scannerItem{
        regexp.MustCompile(`null`),
        S_NIL,
    },
    scannerItem{
        regexp.MustCompile(`n`),
        S_PVAR,
    },
    scannerItem{
        regexp.MustCompile(`odd|even`),
        S_KEYWORD,
    },
}

var EXPRESSION_SCANNER = []scannerItem{
    scannerItem{
        regexp.MustCompile(`\s`),
        S_KEYWORD,
    },
    scannerItem{
        regexp.MustCompile(`true`),
        S_BOOL,
    },
    scannerItem{
        regexp.MustCompile(`null`),
        S_NIL,
    },
    scannerItem{
        regexp.MustCompile(`-?\d+(\.\d*)?([eE][+\-]?\d+)?`),
        S_NUMBER,
    },
    scannerItem{
        regexp.MustCompile(`\"([^\]|\[^\"])*\"`),
        S_STRING,
    },
    scannerItem{
        regexp.MustCompile(`x`),
        S_PVAR,
    },
    scannerItem{
        regexp.MustCompile(`(&&|\|\||[\$\^<>!\*]=|[=+\-*/%<>])`),
        S_BINOP,
    },
    scannerItem{
        regexp.MustCompile(`\(|\)`),
        S_PAREN,
    },
}

func lexNextToken(input string, scanners []scannerItem) (*token, int, error) {
    for _, scanner := range scanners {
        idx := scanner.regex.FindStringIndex(input)
        if idx == nil {
            continue
        }
        if idx[0] == 0 {
            if scanner.typ == S_EXPR && strings.Count(input[idx[0]:idx[1]], "(") != strings.Count(input[idx[0]:idx[1]], ")") {
                terminated := false
                var curr int
                for curr = idx[1]; curr <= len(input[idx[0]:]); curr++ {
                    if strings.Count(input[idx[0]:curr], "(") == strings.Count(input[idx[0]:curr], ")") {
                        terminated = true
                        break
                    }
                }
                if terminated == false {
                    return nil, len(input), errors.New(fmt.Sprintf("Unterminated expression: %s", input[idx[0]:curr-1]))
                } else {
                    idx[1] = curr
                }
            }
            token := getToken(
                scanner.typ,
                input[idx[0]:idx[1]],
            )
            return &token, idx[1], nil
        }
    }
    return nil, len(input), errors.New(fmt.Sprintf("Parsing error at %s", input))
}

func Lex(input string, scanners []scannerItem) ([]*token, error) {
    var tokens []*token
    var start = 0
    for start < len(input) {
        token, new_value, err := lexNextToken(input[start:], scanners)
        if err != nil {
            return nil, err
        }
        start = start + new_value
        if token.typ != S_EMPTY {
            tokens = append(
                tokens,
                token,
            )
        }
    }
    logger.Print("Tokenization results: ", input)
    for i, token := range tokens {
        logger.Print("[", i, "] ", token)
    }
    return tokens, nil
}

func getToken(typ tokenType, val string) token {
    switch typ {
        case S_IDENTIFIER, S_PCLASS, S_PCLASS_FUNC, S_NTH_FUNC:
            return token{typ, val[1:]}
        case S_QUOTED_IDENTIFIER:
            return token{S_IDENTIFIER, val[2:len(val)-1]}
        case S_NIL:
            return token{typ, nil}
        case S_BOOL:
            result, _ := strconv.ParseBool(val)
            return token{typ, result}
        case S_NUMBER:
            result, _ := strconv.ParseInt(val, 10, 64)
            return token{typ, result}
        case S_EMPTY:
            return token{typ, " "}
        case S_FLOAT:
            result, _ := strconv.ParseFloat(val, 32)
            return token{typ, result}
        case S_WORD:
            return token{typ, val[1:len(val)-1]}
        default:
            return token{typ, val}
    }
}
<|endoftext|>


<commit_before>package ginkgo

import (
	"math/rand"
)

type node interface {
	//flesh me out!  both containerNodes and itNodes need to satisfy this (but not runnables)
	isContainerNode() bool
	isItNode() bool
}

type containerNode struct {
	flag         flagType
	text         string
	codeLocation CodeLocation

	beforeEachNodes     []*runnableNode
	justBeforeEachNodes []*runnableNode
	afterEachNodes      []*runnableNode
	itAndContainerNodes []node
}

func newContainerNode(text string, flag flagType, codeLocation CodeLocation) *containerNode {
	return &containerNode{
		text:         text,
		flag:         flag,
		codeLocation: codeLocation,
	}
}

func (container *containerNode) shuffle(r *rand.Rand) {
	permutation := r.Perm(len(container.itAndContainerNodes))
	shuffledNodes := make([]node, len(container.itAndContainerNodes))
	for i, j := range permutation {
		shuffledNodes[i] = container.itAndContainerNodes[j]
	}
	container.itAndContainerNodes = shuffledNodes
}

func (node *containerNode) generateExamples() []*example {
	examples := make([]*example, 0)

	for _, containerOrIt := range node.itAndContainerNodes {
		if containerOrIt.isContainerNode() {
			container := containerOrIt.(*containerNode)
			examples = append(examples, container.generateExamples()...)
		} else {
			examples = append(examples, newExample(containerOrIt.(*itNode)))
		}
	}

	for _, example := range examples {
		example.addContainerNode(node)
	}

	return examples
}

func (node *containerNode) pushContainerNode(container *containerNode) {
	node.itAndContainerNodes = append(node.itAndContainerNodes, container)
}

func (node *containerNode) pushItNode(it *itNode) {
	node.itAndContainerNodes = append(node.itAndContainerNodes, it)
}

func (node *containerNode) pushBeforeEachNode(beforeEach *runnableNode) {
	node.beforeEachNodes = append(node.beforeEachNodes, beforeEach)
}

func (node *containerNode) pushJustBeforeEachNode(justBeforeEach *runnableNode) {
	node.justBeforeEachNodes = append(node.justBeforeEachNodes, justBeforeEach)
}

func (node *containerNode) pushAfterEachNode(afterEach *runnableNode) {
	node.afterEachNodes = append(node.afterEachNodes, afterEach)
}

func (node *containerNode) isContainerNode() bool {
	return true
}

func (node *containerNode) isItNode() bool {
	return false
}
<commit_msg>removed unnecessary comment<commit_after>package ginkgo

import (
	"math/rand"
)

type node interface {
	isContainerNode() bool
	isItNode() bool
}

type containerNode struct {
	flag         flagType
	text         string
	codeLocation CodeLocation

	beforeEachNodes     []*runnableNode
	justBeforeEachNodes []*runnableNode
	afterEachNodes      []*runnableNode
	itAndContainerNodes []node
}

func newContainerNode(text string, flag flagType, codeLocation CodeLocation) *containerNode {
	return &containerNode{
		text:         text,
		flag:         flag,
		codeLocation: codeLocation,
	}
}

func (container *containerNode) shuffle(r *rand.Rand) {
	permutation := r.Perm(len(container.itAndContainerNodes))
	shuffledNodes := make([]node, len(container.itAndContainerNodes))
	for i, j := range permutation {
		shuffledNodes[i] = container.itAndContainerNodes[j]
	}
	container.itAndContainerNodes = shuffledNodes
}

func (node *containerNode) generateExamples() []*example {
	examples := make([]*example, 0)

	for _, containerOrIt := range node.itAndContainerNodes {
		if containerOrIt.isContainerNode() {
			container := containerOrIt.(*containerNode)
			examples = append(examples, container.generateExamples()...)
		} else {
			examples = append(examples, newExample(containerOrIt.(*itNode)))
		}
	}

	for _, example := range examples {
		example.addContainerNode(node)
	}

	return examples
}

func (node *containerNode) pushContainerNode(container *containerNode) {
	node.itAndContainerNodes = append(node.itAndContainerNodes, container)
}

func (node *containerNode) pushItNode(it *itNode) {
	node.itAndContainerNodes = append(node.itAndContainerNodes, it)
}

func (node *containerNode) pushBeforeEachNode(beforeEach *runnableNode) {
	node.beforeEachNodes = append(node.beforeEachNodes, beforeEach)
}

func (node *containerNode) pushJustBeforeEachNode(justBeforeEach *runnableNode) {
	node.justBeforeEachNodes = append(node.justBeforeEachNodes, justBeforeEach)
}

func (node *containerNode) pushAfterEachNode(afterEach *runnableNode) {
	node.afterEachNodes = append(node.afterEachNodes, afterEach)
}

func (node *containerNode) isContainerNode() bool {
	return true
}

func (node *containerNode) isItNode() bool {
	return false
}
<|endoftext|>


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

// author           xeipuuv
// author-github    https://github.com/xeipuuv
// author-mail      xeipuuv@gmail.com
//
// repository-name  gojsonschema
// repository-desc  An implementation of JSON Schema, based on IETF's draft v4 - Go language.
//
// description      Result and ResultError implementations.
//
// created          01-01-2015

package gojsonschema

import (
	"fmt"
	"strings"
)

type (
	// ErrorDetails is a map of details specific to each error.
	// While the values will vary, every error will contain a "field" value
	ErrorDetails map[string]interface{}

	// ResultError is the interface that library errors must implement
	ResultError interface {
		Field() string
		SetType(string)
		Type() string
		SetContext(*jsonContext)
		Context() *jsonContext
		SetDescription(string)
		Description() string
		SetValue(interface{})
		Value() interface{}
		SetDetails(ErrorDetails)
		Details() ErrorDetails
	}

	// ResultErrorFields holds the fields for each ResultError implementation.
	// ResultErrorFields implements the ResultError interface, so custom errors
	// can be defined by just embedding this type
	ResultErrorFields struct {
		errorType   string       // A string with the type of error (i.e. invalid_type)
		context     *jsonContext // Tree like notation of the part that failed the validation. ex (root).a.b ...
		description string       // A human readable error message
		value       interface{}  // Value given by the JSON file that is the source of the error
		details     ErrorDetails
	}

	Result struct {
		errors []ResultError
		// Scores how well the validation matched. Useful in generating
		// better error messages for anyOf and oneOf.
		score int
	}
)

// Field outputs the field name without the root context
// i.e. firstName or person.firstName instead of (root).firstName or (root).person.firstName
func (v *ResultErrorFields) Field() string {
	if p, ok := v.Details()["property"]; ok {
		if str, isString := p.(string); isString {
			return str
		}
	}

	return strings.TrimLeft(v.context.String(), STRING_ROOT_SCHEMA_PROPERTY+".")
}

func (v *ResultErrorFields) SetType(errorType string) {
	v.errorType = errorType
}

func (v *ResultErrorFields) Type() string {
	return v.errorType
}

func (v *ResultErrorFields) SetContext(context *jsonContext) {
	v.context = context
}

func (v *ResultErrorFields) Context() *jsonContext {
	return v.context
}

func (v *ResultErrorFields) SetDescription(description string) {
	v.description = description
}

func (v *ResultErrorFields) Description() string {
	return v.description
}

func (v *ResultErrorFields) SetValue(value interface{}) {
	v.value = value
}

func (v *ResultErrorFields) Value() interface{} {
	return v.value
}

func (v *ResultErrorFields) SetDetails(details ErrorDetails) {
	v.details = details
}

func (v *ResultErrorFields) Details() ErrorDetails {
	return v.details
}

func (v ResultErrorFields) String() string {
	// as a fallback, the value is displayed go style
	valueString := fmt.Sprintf("%v", v.value)

	// marshal the go value value to json
	if v.Value == nil {
		valueString = TYPE_NULL
	} else {
		if vs, err := marshalToJsonString(v.value); err == nil {
			if vs == nil {
				valueString = TYPE_NULL
			} else {
				valueString = *vs
			}
		}
	}

	return formatErrorDescription(Locale.ErrorFormat(), ErrorDetails{
		"context":     v.context.String(),
		"description": v.description,
		"value":       valueString,
		"field":       v.Field(),
	})
}

func (v *Result) Valid() bool {
	return len(v.errors) == 0
}

func (v *Result) Errors() []ResultError {
	return v.errors
}

func (v *Result) addError(err ResultError, context *jsonContext, value interface{}, details ErrorDetails) {
	newError(err, context, value, Locale, details)
	v.errors = append(v.errors, err)
	v.score -= 2 // results in a net -1 when added to the +1 we get at the end of the validation function
}

// Used to copy errors from a sub-schema to the main one
func (v *Result) mergeErrors(otherResult *Result) {
	v.errors = append(v.errors, otherResult.Errors()...)
	v.score += otherResult.score
}

func (v *Result) incrementScore() {
	v.score++
}
<commit_msg>Extra character trim bugfix<commit_after>// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// author           xeipuuv
// author-github    https://github.com/xeipuuv
// author-mail      xeipuuv@gmail.com
//
// repository-name  gojsonschema
// repository-desc  An implementation of JSON Schema, based on IETF's draft v4 - Go language.
//
// description      Result and ResultError implementations.
//
// created          01-01-2015

package gojsonschema

import (
	"fmt"
	"strings"
)

type (
	// ErrorDetails is a map of details specific to each error.
	// While the values will vary, every error will contain a "field" value
	ErrorDetails map[string]interface{}

	// ResultError is the interface that library errors must implement
	ResultError interface {
		Field() string
		SetType(string)
		Type() string
		SetContext(*jsonContext)
		Context() *jsonContext
		SetDescription(string)
		Description() string
		SetValue(interface{})
		Value() interface{}
		SetDetails(ErrorDetails)
		Details() ErrorDetails
	}

	// ResultErrorFields holds the fields for each ResultError implementation.
	// ResultErrorFields implements the ResultError interface, so custom errors
	// can be defined by just embedding this type
	ResultErrorFields struct {
		errorType   string       // A string with the type of error (i.e. invalid_type)
		context     *jsonContext // Tree like notation of the part that failed the validation. ex (root).a.b ...
		description string       // A human readable error message
		value       interface{}  // Value given by the JSON file that is the source of the error
		details     ErrorDetails
	}

	Result struct {
		errors []ResultError
		// Scores how well the validation matched. Useful in generating
		// better error messages for anyOf and oneOf.
		score int
	}
)

// Field outputs the field name without the root context
// i.e. firstName or person.firstName instead of (root).firstName or (root).person.firstName
func (v *ResultErrorFields) Field() string {
	if p, ok := v.Details()["property"]; ok {
		if str, isString := p.(string); isString {
			return str
		}
	}

	return strings.TrimPrefix(v.context.String(), STRING_ROOT_SCHEMA_PROPERTY+".")
}

func (v *ResultErrorFields) SetType(errorType string) {
	v.errorType = errorType
}

func (v *ResultErrorFields) Type() string {
	return v.errorType
}

func (v *ResultErrorFields) SetContext(context *jsonContext) {
	v.context = context
}

func (v *ResultErrorFields) Context() *jsonContext {
	return v.context
}

func (v *ResultErrorFields) SetDescription(description string) {
	v.description = description
}

func (v *ResultErrorFields) Description() string {
	return v.description
}

func (v *ResultErrorFields) SetValue(value interface{}) {
	v.value = value
}

func (v *ResultErrorFields) Value() interface{} {
	return v.value
}

func (v *ResultErrorFields) SetDetails(details ErrorDetails) {
	v.details = details
}

func (v *ResultErrorFields) Details() ErrorDetails {
	return v.details
}

func (v ResultErrorFields) String() string {
	// as a fallback, the value is displayed go style
	valueString := fmt.Sprintf("%v", v.value)

	// marshal the go value value to json
	if v.Value == nil {
		valueString = TYPE_NULL
	} else {
		if vs, err := marshalToJsonString(v.value); err == nil {
			if vs == nil {
				valueString = TYPE_NULL
			} else {
				valueString = *vs
			}
		}
	}

	return formatErrorDescription(Locale.ErrorFormat(), ErrorDetails{
		"context":     v.context.String(),
		"description": v.description,
		"value":       valueString,
		"field":       v.Field(),
	})
}

func (v *Result) Valid() bool {
	return len(v.errors) == 0
}

func (v *Result) Errors() []ResultError {
	return v.errors
}

func (v *Result) addError(err ResultError, context *jsonContext, value interface{}, details ErrorDetails) {
	newError(err, context, value, Locale, details)
	v.errors = append(v.errors, err)
	v.score -= 2 // results in a net -1 when added to the +1 we get at the end of the validation function
}

// Used to copy errors from a sub-schema to the main one
func (v *Result) mergeErrors(otherResult *Result) {
	v.errors = append(v.errors, otherResult.Errors()...)
	v.score += otherResult.score
}

func (v *Result) incrementScore() {
	v.score++
}
<|endoftext|>


<commit_before>// Copyright 2017 The tcp-srv Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package sensors exposes sensor data.
package sensors

import (
	"fmt"
	"log"
	"time"

	"github.com/go-daq/smbus"
	"github.com/go-daq/smbus/sensor/at30tse75x"
	"github.com/go-daq/smbus/sensor/bme280"
	"github.com/go-daq/smbus/sensor/hts221"
	"github.com/go-daq/smbus/sensor/tsl2591"
)

type Sensors struct {
	Timestamp time.Time `json:"timestamp"`
	Tsl       Tsl       `json:"tsl"`
	Bme       Bme       `json:"bme280"`
	At30tse   At30tse   `json:"at30tse"`
	Hts221    Hts221    `json:"hts221"`
}

func New(bus *smbus.Conn, addr uint8) (Sensors, error) {
	data := Sensors{
		Timestamp: time.Now().UTC(),
	}
	err := data.read(bus, addr)
	if err != nil {
		return Sensors{}, err
	}
	return data, nil
}

func (s *Sensors) read(bus *smbus.Conn, addr uint8) error {
	var err error
	err = s.Tsl.read(bus, addr, 0x80)
	if err != nil {
		return fmt.Errorf("tsl error: %v", err)
	}
	err = s.Bme.read(bus, addr, 0x80)
	if err != nil {
		return fmt.Errorf("bme error: %v", err)
	}
	err = s.At30tse.read(bus, addr, 0x08)
	if err != nil {
		return fmt.Errorf("at30tse error: %v", err)
	}
	err = s.Hts221.read(bus, addr, 0x02)
	if err != nil {
		return fmt.Errorf("hts221 error: %v", err)
	}
	return err
}

type Tsl struct {
	Lux  float64 `json:"lux"`
	Full uint16  `json:"full"`
	IR   uint16  `json:"ir"`
}

func (tsl *Tsl) read(bus *smbus.Conn, addr uint8, ch uint8) error {
	err := bus.WriteReg(addr, 0x04, ch)
	if err != nil {
		log.Printf("tsl-write-reg error: %v", err)
		return err
	}

	dev, err := tsl2591.Open(bus, tsl2591.Addr, tsl2591.IntegTime100ms, tsl2591.GainLow)
	if err != nil {
		log.Printf("tsl-open-bus error: %v", err)
		return err
	}

	full, ir, err := dev.FullLuminosity()
	if err != nil {
		log.Printf("tsl-sample error: %v", err)
		return err
	}

	tsl.Lux = dev.Lux(full, ir)
	tsl.Full = full
	tsl.IR = ir

	return err
}

type Bme struct {
	Temp float64 `json:"temp"`
	Hum  float64 `json:"hum"`
	Pres float64 `json:"pres"`
}

func (bme *Bme) read(bus *smbus.Conn, addr uint8, ch uint8) error {
	err := bus.WriteReg(addr, 0x04, ch)
	if err != nil {
		log.Printf("write-reg error: %v", err)
		return err
	}

	dev, err := bme280.Open(bus, bme280.I2CAddr, bme280.OpSample8)
	if err != nil {
		log.Printf("open-bus error (i2c-addr=0x%x): %v", bme280.I2CAddr, err)
		return err
	}

	h, p, t, err := dev.Sample()
	if err != nil {
		log.Printf("sample error: %v", err)
		return err
	}

	const HPa = 1.0 / 100.0
	bme.Hum = h
	bme.Pres = p * HPa
	bme.Temp = t

	return err
}

type At30tse struct {
	Temp float64 `json:"temp"`
}

func (at30 *At30tse) read(bus *smbus.Conn, addr uint8, ch uint8) error {
	err := bus.WriteReg(addr, 0x04, ch)
	if err != nil {
		log.Printf("at30tse-write-reg error: %v", err)
		return err
	}

	const eeprom = 4
	dev, err := at30tse75x.Open(bus, 0, eeprom)
	if err != nil {
		log.Printf("at30tse-open-bus error: %v", err)
		return err
	}

	t, err := dev.T()
	if err != nil {
		log.Printf("at30tse-sample error: %v", err)
		return err
	}
	at30.Temp = t
	return nil
}

type Hts221 struct {
	Temp float64 `json:"temp"`
	Humi float64 `json:"humidity"`
}

func (hts *Hts221) read(bus *smbus.Conn, addr uint8, ch uint8) error {
	err := bus.WriteReg(addr, 0x04, ch)
	if err != nil {
		log.Printf("hts221-write-reg error: %v", err)
		return err
	}

	dev, err := hts221.Open(bus, hts221.SlaveAddr)
	if err != nil {
		log.Printf("hts221-open-bus error: %v", err)
		return err
	}

	h, t, err := dev.Sample()
	if err != nil {
		log.Printf("hts221-sample error: %v", err)
		return err
	}
	hts.Temp = t
	hts.Humi = h
	return nil
}
<commit_msg>tcp-srv/sensors: harmonize and streamline naming conventions<commit_after>// Copyright 2017 The tcp-srv Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package sensors exposes sensor data.
package sensors

import (
	"fmt"
	"log"
	"time"

	"github.com/go-daq/smbus"
	"github.com/go-daq/smbus/sensor/at30tse75x"
	"github.com/go-daq/smbus/sensor/bme280"
	"github.com/go-daq/smbus/sensor/hts221"
	"github.com/go-daq/smbus/sensor/tsl2591"
)

type Sensors struct {
	Timestamp  time.Time  `json:"timestamp"`
	Tsl2591    Tsl2591    `json:"tsl2591"`
	Bme280     Bme280     `json:"bme280"`
	At30tse75x At30tse75x `json:"at30tse75x"`
	Hts221     Hts221     `json:"hts221"`
}

func New(bus *smbus.Conn, addr uint8) (Sensors, error) {
	data := Sensors{
		Timestamp: time.Now().UTC(),
	}
	err := data.read(bus, addr)
	if err != nil {
		return Sensors{}, err
	}
	return data, nil
}

func (s *Sensors) read(bus *smbus.Conn, addr uint8) error {
	var err error
	err = s.Tsl2591.read(bus, addr, 0x80)
	if err != nil {
		return fmt.Errorf("tsl error: %v", err)
	}
	err = s.Bme280.read(bus, addr, 0x80)
	if err != nil {
		return fmt.Errorf("bme error: %v", err)
	}
	err = s.At30tse75x.read(bus, addr, 0x08)
	if err != nil {
		return fmt.Errorf("at30tse error: %v", err)
	}
	err = s.Hts221.read(bus, addr, 0x02)
	if err != nil {
		return fmt.Errorf("hts221 error: %v", err)
	}
	return err
}

type Tsl2591 struct {
	Lux  float64 `json:"lux"`
	Full uint16  `json:"full"`
	IR   uint16  `json:"ir"`
}

func (tsl *Tsl2591) read(bus *smbus.Conn, addr uint8, ch uint8) error {
	err := bus.WriteReg(addr, 0x04, ch)
	if err != nil {
		log.Printf("tsl-write-reg error: %v", err)
		return err
	}

	dev, err := tsl2591.Open(bus, tsl2591.Addr, tsl2591.IntegTime100ms, tsl2591.GainLow)
	if err != nil {
		log.Printf("tsl-open-bus error: %v", err)
		return err
	}

	full, ir, err := dev.FullLuminosity()
	if err != nil {
		log.Printf("tsl-sample error: %v", err)
		return err
	}

	tsl.Lux = dev.Lux(full, ir)
	tsl.Full = full
	tsl.IR = ir

	return err
}

type Bme280 struct {
	Temp float64 `json:"temp"`
	Hum  float64 `json:"humi"`
	Pres float64 `json:"pres"`
}

func (bme *Bme280) read(bus *smbus.Conn, addr uint8, ch uint8) error {
	err := bus.WriteReg(addr, 0x04, ch)
	if err != nil {
		log.Printf("write-reg error: %v", err)
		return err
	}

	dev, err := bme280.Open(bus, bme280.I2CAddr, bme280.OpSample8)
	if err != nil {
		log.Printf("open-bus error (i2c-addr=0x%x): %v", bme280.I2CAddr, err)
		return err
	}

	h, p, t, err := dev.Sample()
	if err != nil {
		log.Printf("sample error: %v", err)
		return err
	}

	const HPa = 1.0 / 100.0
	bme.Hum = h
	bme.Pres = p * HPa
	bme.Temp = t

	return err
}

type At30tse75x struct {
	Temp float64 `json:"temp"`
}

func (at30 *At30tse75x) read(bus *smbus.Conn, addr uint8, ch uint8) error {
	err := bus.WriteReg(addr, 0x04, ch)
	if err != nil {
		log.Printf("at30tse-write-reg error: %v", err)
		return err
	}

	const eeprom = 4
	dev, err := at30tse75x.Open(bus, 0, eeprom)
	if err != nil {
		log.Printf("at30tse-open-bus error: %v", err)
		return err
	}

	t, err := dev.T()
	if err != nil {
		log.Printf("at30tse-sample error: %v", err)
		return err
	}
	at30.Temp = t
	return nil
}

type Hts221 struct {
	Temp float64 `json:"temp"`
	Humi float64 `json:"humi"`
}

func (hts *Hts221) read(bus *smbus.Conn, addr uint8, ch uint8) error {
	err := bus.WriteReg(addr, 0x04, ch)
	if err != nil {
		log.Printf("hts221-write-reg error: %v", err)
		return err
	}

	dev, err := hts221.Open(bus, hts221.SlaveAddr)
	if err != nil {
		log.Printf("hts221-open-bus error: %v", err)
		return err
	}

	h, t, err := dev.Sample()
	if err != nil {
		log.Printf("hts221-sample error: %v", err)
		return err
	}
	hts.Temp = t
	hts.Humi = h
	return nil
}
<|endoftext|>


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

package oglemock

import (
	"errors"
	"fmt"
	"math"
	"reflect"
)

var intType = reflect.TypeOf(int(0))
var float64Type = reflect.TypeOf(float64(0))
var complex128Type = reflect.TypeOf(complex128(0))

// Return creates an Action that returns the values passed to Return as
// arguments, after suitable legal type conversions. The following rules apply.
// Given an argument x to Return and a corresponding type T in the method's
// signature, at least one of the following must hold:
//
//  *  x is assignable to T. (See "Assignability" in the language spec.) Note
//     that this in particular applies that x may be a type that implements an
//     interface T. It also implies that the nil literal can be used if T is a
//     pointer, function, interface, slice, channel, or map type.
//
//  *  T is any numeric type, and x is an int that is in-range for that type.
//     This facilities using raw integer constants: Return(17).
//
//  *  T is a floating-point or complex number type, and x is a float64.  This
//     facilities using raw floating-point constants: Return(17.5).
//
//  *  T is a complex number type, and x is a complex128. This facilities using
//     raw complex constants: Return(17+2i).
//
func Return(vals ...interface{}) Action {
	return &returnAction{vals, nil}
}

type returnAction struct {
	returnVals []interface{}
	signature reflect.Type
}

func (a *returnAction) Invoke(vals []interface{}) []interface{} {
	return a.returnVals
}

func (a *returnAction) SetSignature(signature reflect.Type) error {
	if _, err := a.buildInvokeResult(signature); err != nil {
		return err
	}

	a.signature = signature
	return nil
}

// A version of Invoke that does error checking, used by both public methods.
func (a *returnAction) buildInvokeResult(
	sig reflect.Type) (res []interface{}, err error) {
	// Check the length of the return value.
	numOut := sig.NumOut()
	numVals := len(a.returnVals)

	if numOut != numVals {
		err = errors.New(
			fmt.Sprintf("Return given %d vals; expected %d.", numVals, numOut))
		return
	}

	// Attempt to coerce each return value.
	res = make([]interface{}, numOut)

	for i, val := range a.returnVals {
		resType := sig.Out(i)
		res[i], err = a.coerce(val, resType)

		if err != nil {
			res = nil
			err = errors.New(fmt.Sprintf("Return: arg %d: %v", i, err))
			return
		}
	}

	return
}

func (a *returnAction) coerce(x interface{}, t reflect.Type) (interface{}, error) {
	xv := reflect.ValueOf(x)
	rv := reflect.New(t).Elem()

	// Special case: the language spec says that the predeclared identifier nil
	// is assignable to pointers, functions, interface, slices, channels, and map
	// types. However, reflect.ValueOf(nil) returns an invalid value that will
	// not cooperate below. So handle invalid values here, assuming that they
	// resulted from Return(nil).
	if !xv.IsValid() {
		switch t.Kind() {
		case reflect.Ptr, reflect.Func, reflect.Interface, reflect.Chan, reflect.Slice, reflect.Map:
			return rv.Interface(), nil
		}

		return nil, errors.New(fmt.Sprintf("expected %v, given <nil>", t))
	}

	// If x is assignable to type t, let the reflect package do the heavy
	// lifting.
	if reflect.TypeOf(x).AssignableTo(t) {
		rv.Set(xv)
		return rv.Interface(), nil
	}

	// Handle numeric types as described in the documentation on Return.
	switch {
	case xv.Type() == intType && a.isNumeric(t):
		return a.coerceInt(xv.Int(), t)

	case xv.Type() == float64Type && (a.isFloatingPoint(t) || a.isComplex(t)):
		return a.coerceFloat(xv.Float(), t)

	case xv.Type() == complex128Type && a.isComplex(t):
		return a.coerceComplex(xv.Complex(), t)
	}

	// The value wasn't of a legal type.
	return nil, errors.New(fmt.Sprintf("expected %v, given %v", t, xv.Type()))
}

func (a *returnAction) isNumeric(t reflect.Type) bool {
	return (t.Kind() >= reflect.Int && t.Kind() <= reflect.Uint64) ||
		a.isFloatingPoint(t) ||
		a.isComplex(t)
}

func (a *returnAction) isFloatingPoint(t reflect.Type) bool {
	return t.Kind() == reflect.Float32 || t.Kind() == reflect.Float64
}

func (a *returnAction) isComplex(t reflect.Type) bool {
	return t.Kind() == reflect.Complex64 || t.Kind() == reflect.Complex128
}

func (a *returnAction) coerceInt(x int64, t reflect.Type) (interface{}, error) {
	k := t.Kind()

	// Floating point and complex numbers: promote appropriately.
	if a.isFloatingPoint(t) || a.isComplex(t) {
		return a.coerceFloat(float64(x), t)
	}

	// Integers: range check.
	min := int64(math.MinInt64)
	max := int64(math.MaxInt64)

	switch {
	case k == reflect.Int8:
		min = math.MinInt8
		max = math.MaxInt8

	case k == reflect.Int16:
		min = math.MinInt16
		max = math.MaxInt16

	case k == reflect.Int32:
		min = math.MinInt32
		max = math.MaxInt32

	case k >= reflect.Uint && k <= reflect.Uint64:  // Unsigned
		min = 0
	}

	if x < min || x > max {
		return nil, errors.New("int value out of range")
	}

	rv := reflect.New(t).Elem()
	rv.SetInt(x)

	return rv.Interface(), nil
}

func (a *returnAction) coerceFloat(x float64, t reflect.Type) (interface{}, error) {
	return nil, errors.New("TODO")
}

func (a *returnAction) coerceComplex(x complex128, t reflect.Type) (interface{}, error) {
	return nil, errors.New("TODO")
}
<commit_msg>Implemented Invoke.<commit_after>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package oglemock

import (
	"errors"
	"fmt"
	"math"
	"reflect"
)

var intType = reflect.TypeOf(int(0))
var float64Type = reflect.TypeOf(float64(0))
var complex128Type = reflect.TypeOf(complex128(0))

// Return creates an Action that returns the values passed to Return as
// arguments, after suitable legal type conversions. The following rules apply.
// Given an argument x to Return and a corresponding type T in the method's
// signature, at least one of the following must hold:
//
//  *  x is assignable to T. (See "Assignability" in the language spec.) Note
//     that this in particular applies that x may be a type that implements an
//     interface T. It also implies that the nil literal can be used if T is a
//     pointer, function, interface, slice, channel, or map type.
//
//  *  T is any numeric type, and x is an int that is in-range for that type.
//     This facilities using raw integer constants: Return(17).
//
//  *  T is a floating-point or complex number type, and x is a float64.  This
//     facilities using raw floating-point constants: Return(17.5).
//
//  *  T is a complex number type, and x is a complex128. This facilities using
//     raw complex constants: Return(17+2i).
//
func Return(vals ...interface{}) Action {
	return &returnAction{vals, nil}
}

type returnAction struct {
	returnVals []interface{}
	signature reflect.Type
}

func (a *returnAction) Invoke(vals []interface{}) []interface{} {
	res, err := a.buildInvokeResult(a.signature)
	if err != nil {
		panic(err)
	}

	return res
}

func (a *returnAction) SetSignature(signature reflect.Type) error {
	if _, err := a.buildInvokeResult(signature); err != nil {
		return err
	}

	a.signature = signature
	return nil
}

// A version of Invoke that does error checking, used by both public methods.
func (a *returnAction) buildInvokeResult(
	sig reflect.Type) (res []interface{}, err error) {
	// Check the length of the return value.
	numOut := sig.NumOut()
	numVals := len(a.returnVals)

	if numOut != numVals {
		err = errors.New(
			fmt.Sprintf("Return given %d vals; expected %d.", numVals, numOut))
		return
	}

	// Attempt to coerce each return value.
	res = make([]interface{}, numOut)

	for i, val := range a.returnVals {
		resType := sig.Out(i)
		res[i], err = a.coerce(val, resType)

		if err != nil {
			res = nil
			err = errors.New(fmt.Sprintf("Return: arg %d: %v", i, err))
			return
		}
	}

	return
}

func (a *returnAction) coerce(x interface{}, t reflect.Type) (interface{}, error) {
	xv := reflect.ValueOf(x)
	rv := reflect.New(t).Elem()

	// Special case: the language spec says that the predeclared identifier nil
	// is assignable to pointers, functions, interface, slices, channels, and map
	// types. However, reflect.ValueOf(nil) returns an invalid value that will
	// not cooperate below. So handle invalid values here, assuming that they
	// resulted from Return(nil).
	if !xv.IsValid() {
		switch t.Kind() {
		case reflect.Ptr, reflect.Func, reflect.Interface, reflect.Chan, reflect.Slice, reflect.Map:
			return rv.Interface(), nil
		}

		return nil, errors.New(fmt.Sprintf("expected %v, given <nil>", t))
	}

	// If x is assignable to type t, let the reflect package do the heavy
	// lifting.
	if reflect.TypeOf(x).AssignableTo(t) {
		rv.Set(xv)
		return rv.Interface(), nil
	}

	// Handle numeric types as described in the documentation on Return.
	switch {
	case xv.Type() == intType && a.isNumeric(t):
		return a.coerceInt(xv.Int(), t)

	case xv.Type() == float64Type && (a.isFloatingPoint(t) || a.isComplex(t)):
		return a.coerceFloat(xv.Float(), t)

	case xv.Type() == complex128Type && a.isComplex(t):
		return a.coerceComplex(xv.Complex(), t)
	}

	// The value wasn't of a legal type.
	return nil, errors.New(fmt.Sprintf("expected %v, given %v", t, xv.Type()))
}

func (a *returnAction) isNumeric(t reflect.Type) bool {
	return (t.Kind() >= reflect.Int && t.Kind() <= reflect.Uint64) ||
		a.isFloatingPoint(t) ||
		a.isComplex(t)
}

func (a *returnAction) isFloatingPoint(t reflect.Type) bool {
	return t.Kind() == reflect.Float32 || t.Kind() == reflect.Float64
}

func (a *returnAction) isComplex(t reflect.Type) bool {
	return t.Kind() == reflect.Complex64 || t.Kind() == reflect.Complex128
}

func (a *returnAction) coerceInt(x int64, t reflect.Type) (interface{}, error) {
	k := t.Kind()

	// Floating point and complex numbers: promote appropriately.
	if a.isFloatingPoint(t) || a.isComplex(t) {
		return a.coerceFloat(float64(x), t)
	}

	// Integers: range check.
	min := int64(math.MinInt64)
	max := int64(math.MaxInt64)

	switch {
	case k == reflect.Int8:
		min = math.MinInt8
		max = math.MaxInt8

	case k == reflect.Int16:
		min = math.MinInt16
		max = math.MaxInt16

	case k == reflect.Int32:
		min = math.MinInt32
		max = math.MaxInt32

	case k >= reflect.Uint && k <= reflect.Uint64:  // Unsigned
		min = 0
	}

	if x < min || x > max {
		return nil, errors.New("int value out of range")
	}

	rv := reflect.New(t).Elem()
	rv.SetInt(x)

	return rv.Interface(), nil
}

func (a *returnAction) coerceFloat(x float64, t reflect.Type) (interface{}, error) {
	return nil, errors.New("TODO")
}

func (a *returnAction) coerceComplex(x complex128, t reflect.Type) (interface{}, error) {
	return nil, errors.New("TODO")
}
<|endoftext|>