{{ define "main" }}
{{- /*gotype: github.com/go-faster/jx/tools/mkint.Config*/ -}}
// Code generated by mkint, DO NOT EDIT.

package {{ $.PackageName }}

import (
	"io"
	"math"
	"strconv"

	"github.com/go-faster/errors"
)


var errOverflow = strconv.ErrRange

const (
	uint8SafeToMultiple10  = uint8(0xff)/10 - 1
	uint16SafeToMultiple10 = uint16(0xffff)/10 - 1
	uint32SafeToMultiple10 = uint32(0xffffffff)/10 - 1
	uint64SafeToMultiple10 = uint64(0xffffffffffffffff)/10 - 1
)

{{ range $typ := $.Types }}
	{{ template "decode_uint" $typ }}
	{{ template "decode_int" $typ }}
{{- end }}

{{ end }}

{{ define "decode_uint" }}
{{- /*gotype: github.com/go-faster/jx/tools/mkint.IntType */ -}}
// U{{ title $.Name }} reads u{{ $.Name }}.
func (d *Decoder) U{{ title $.Name }}() (u{{ $.Name }}, error) {
	c, err := d.more()
	if err != nil {
		return 0, err
	}
	return d.readU{{ title $.Name }}(c)
}

func (d *Decoder) readU{{ title $.Name }}(c byte) (u{{ $.Name }}, error) {
	ind := floatDigits[c]
	switch ind {
	case 0:
		// Check that next byte is not a digit.
		c, err := d.peek()
		if err == nil {
			switch floatDigits[c] {
			case 0, 1, 2, 3, 4, 5, 6, 7, 8, 9:
				err := badToken(c, d.offset())
				return 0, errors.Wrap(err, "digit after leading zero")
			case dotInNumber, expInNumber, plusInNumber, minusInNumber:
				err := badToken(c, d.offset())
				return 0, errors.Wrap(err, "unexpected floating point character")
			case invalidCharForNumber:
				return 0, badToken(c, d.offset())
			}
		}
		return 0, nil // single zero
	default:
		if ind < 0 {
			return 0, badToken(c, d.offset()-1)
		}
	}
	value := u{{ $.Name }}(ind)
	if d.tail-d.head > {{ $.DecoderIterations }} {
		i := d.head
	{{- range $i, $_ := times $.DecoderIterations }}
		// Iteration {{ $i }}.
		ind{{ add $i 2 }} := floatDigits[d.buf[i]]
		switch ind{{ add $i 2 }} {
		case invalidCharForNumber:
			return 0, badToken(d.buf[i], d.offset()+{{ $i }})
		case dotInNumber,
			expInNumber,
			plusInNumber,
			minusInNumber:
			err := badToken(d.buf[i], d.offset()+{{ $i }})
			return 0, errors.Wrap(err, "unexpected floating point character")
		case endOfNumber:
			d.head = i
			value *= {{ pow10 $i }}
			{{- range $r, $_ := times $i }}
				value += u{{ $.Name }}(ind{{ add $r 2 }}) * {{ pow10 (sub (sub $i $r) 1) }}
			{{- end }}
			return value, nil
		}

		{{- if eq $i (sub $.DecoderIterations 1) }}
			d.head = i
			value *= {{ pow10 $i }}
			{{- range $r, $_ := times $i }}
				value += u{{ $.Name }}(ind{{ add $r 2 }}) * {{ pow10 (sub (sub $i $r) 1) }}
			{{- end }}
		{{- else }}
			i++
		{{- end }}

	{{- end }}
	}
	for {
		buf := d.buf[d.head:d.tail]
		for i, c := range buf {
			ind = floatDigits[c]
			switch ind {
			case invalidCharForNumber:
				return 0, badToken(c, d.offset()+i)
			case dotInNumber,
				expInNumber,
				plusInNumber,
				minusInNumber:
				err := badToken(c, d.offset()+i)
				return 0, errors.Wrap(err, "unexpected floating point character")
			case endOfNumber:
				d.head += i
				return value, nil
			}
			if value > u{{ $.Name }}SafeToMultiple10 {
				value2 := (value << 3) + (value << 1) + u{{ $.Name }}(ind)
				if value2 < value {
					return 0, errOverflow
				}
				value = value2
				continue
			}
			value = (value << 3) + (value << 1) + u{{ $.Name }}(ind)
		}
		switch err := d.read(); err {
		case io.EOF:
			return value, nil
		case nil:
			continue
		default:
			return 0, err
		}
	}
}
{{ end }}

{{ define "decode_int" }}
{{- /*gotype: github.com/go-faster/jx/tools/mkint.IntType */ -}}
// {{ title $.Name }} reads {{ $.Name }}.
func (d *Decoder) {{ title $.Name }}() ({{ $.Name }}, error) {
	c, err := d.more()
	if err != nil {
		return 0, err
	}
	if c == '-' {
		c, err := d.byte()
		if err != nil {
			return 0, err
		}
		val, err := d.readU{{ title $.Name }}(c)
		if err != nil {
			return 0, err
		}
		if val > math.Max{{ title $.Name }}+1 {
			return 0, errOverflow
		}
		return -{{ $.Name }}(val), nil
	}
	val, err := d.readU{{ title $.Name }}(c)
	if err != nil {
		return 0, err
	}
	if val > math.Max{{ title $.Name }} {
		return 0, errOverflow
	}
	return {{ $.Name }}(val), nil
}
{{ end }}
