update vendor

This commit is contained in:
Alex Wong
2019-03-12 15:00:55 +08:00
parent e48faa9144
commit 1bfcdba499
15 changed files with 2299 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2018 codemodus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+349
View File
@@ -0,0 +1,349 @@
// Package parth provides path parsing for segment unmarshaling and slicing. In
// other words, parth provides simple and flexible access to (URL) path
// parameters.
//
// Along with string, all basic non-alias types are supported. An interface is
// available for implementation by user-defined types. When handling an int,
// uint, or float of any size, the first valid value within the specified
// segment will be used.
package parth
import (
"errors"
)
// Unmarshaler is the interface implemented by types that can unmarshal a path
// segment representation of themselves. It is safe to assume that the segment
// data will not include slashes.
type Unmarshaler interface {
UnmarshalSegment(string) error
}
// Err{Name} values facilitate error identification.
var (
ErrUnknownType = errors.New("unknown type provided")
ErrFirstSegNotFound = errors.New("first segment not found by index")
ErrLastSegNotFound = errors.New("last segment not found by index")
ErrSegOrderReversed = errors.New("first segment must precede last segment")
ErrKeySegNotFound = errors.New("segment not found by key")
ErrDataUnparsable = errors.New("data cannot be parsed")
)
// Segment locates the path segment indicated by the index i and unmarshals it
// into the provided type v. If the index is negative, the negative count
// begins with the last segment. An error is returned if: 1. The type is not a
// pointer to an instance of one of the basic non-alias types and does not
// implement the Unmarshaler interface; 2. The index is out of range of the
// path; 3. The located path segment data cannot be parsed as the provided type
// or if an error is returned when using a provided Unmarshaler implementation.
func Segment(path string, i int, v interface{}) error { //nolint
var err error
switch v := v.(type) {
case *bool:
*v, err = segmentToBool(path, i)
case *float32:
var f float64
f, err = segmentToFloatN(path, i, 32)
*v = float32(f)
case *float64:
*v, err = segmentToFloatN(path, i, 64)
case *int:
var n int64
n, err = segmentToIntN(path, i, 0)
*v = int(n)
case *int16:
var n int64
n, err = segmentToIntN(path, i, 16)
*v = int16(n)
case *int32:
var n int64
n, err = segmentToIntN(path, i, 32)
*v = int32(n)
case *int64:
*v, err = segmentToIntN(path, i, 64)
case *int8:
var n int64
n, err = segmentToIntN(path, i, 8)
*v = int8(n)
case *string:
*v, err = segmentToString(path, i)
case *uint:
var n uint64
n, err = segmentToUintN(path, i, 0)
*v = uint(n)
case *uint16:
var n uint64
n, err = segmentToUintN(path, i, 16)
*v = uint16(n)
case *uint32:
var n uint64
n, err = segmentToUintN(path, i, 32)
*v = uint32(n)
case *uint64:
*v, err = segmentToUintN(path, i, 64)
case *uint8:
var n uint64
n, err = segmentToUintN(path, i, 8)
*v = uint8(n)
case Unmarshaler:
var s string
s, err = segmentToString(path, i)
if err == nil {
err = v.UnmarshalSegment(s)
}
default:
err = ErrUnknownType
}
return err
}
// Sequent is similar to Segment, but uses a key to locate a segment and then
// unmarshal the subsequent segment. It is a simple wrapper over SubSeg with an
// index of 0.
func Sequent(path, key string, v interface{}) error {
return SubSeg(path, key, 0, v)
}
// Span returns the path segments between two segment indexes i and j including
// the first segment. If an index is negative, the negative count begins with
// the last segment. Providing a 0 for the last index j is a special case which
// acts as an alias for the end of the path. If the first segment does not begin
// with a slash and it is part of the requested span, no slash will be added. An
// error is returned if: 1. Either index is out of range of the path; 2. The
// first index i does not precede the last index j.
func Span(path string, i, j int) (string, error) {
var f, l int
var ok bool
if i < 0 {
f, ok = segStartIndexFromEnd(path, i)
} else {
f, ok = segStartIndexFromStart(path, i)
}
if !ok {
return "", ErrFirstSegNotFound
}
if j > 0 {
l, ok = segEndIndexFromStart(path, j)
} else {
l, ok = segEndIndexFromEnd(path, j)
}
if !ok {
return "", ErrLastSegNotFound
}
if f == l {
return "", nil
}
if f > l {
return "", ErrSegOrderReversed
}
return path[f:l], nil
}
// SubSeg is similar to Segment, but only handles the portion of the path
// subsequent to the provided key. For example, to access the segment
// immediately after a key, an index of 0 should be provided (see Sequent). An
// error is returned if the key cannot be found in the path.
func SubSeg(path, key string, i int, v interface{}) error { //nolint
var err error
switch v := v.(type) {
case *bool:
*v, err = subSegToBool(path, key, i)
case *float32:
var f float64
f, err = subSegToFloatN(path, key, i, 32)
*v = float32(f)
case *float64:
*v, err = subSegToFloatN(path, key, i, 64)
case *int:
var n int64
n, err = subSegToIntN(path, key, i, 0)
*v = int(n)
case *int16:
var n int64
n, err = subSegToIntN(path, key, i, 16)
*v = int16(n)
case *int32:
var n int64
n, err = subSegToIntN(path, key, i, 32)
*v = int32(n)
case *int64:
*v, err = subSegToIntN(path, key, i, 64)
case *int8:
var n int64
n, err = subSegToIntN(path, key, i, 8)
*v = int8(n)
case *string:
*v, err = subSegToString(path, key, i)
case *uint:
var n uint64
n, err = subSegToUintN(path, key, i, 0)
*v = uint(n)
case *uint16:
var n uint64
n, err = subSegToUintN(path, key, i, 16)
*v = uint16(n)
case *uint32:
var n uint64
n, err = subSegToUintN(path, key, i, 32)
*v = uint32(n)
case *uint64:
*v, err = subSegToUintN(path, key, i, 64)
case *uint8:
var n uint64
n, err = subSegToUintN(path, key, i, 8)
*v = uint8(n)
case Unmarshaler:
var s string
s, err = subSegToString(path, key, i)
if err == nil {
err = v.UnmarshalSegment(s)
}
default:
err = ErrUnknownType
}
return err
}
// SubSpan is similar to Span, but only handles the portion of the path
// subsequent to the provided key. An error is returned if the key cannot be
// found in the path.
func SubSpan(path, key string, i, j int) (string, error) {
si, ok := segIndexByKey(path, key)
if !ok {
return "", ErrKeySegNotFound
}
if i >= 0 {
i++
}
if j > 0 {
j++
}
s, err := Span(path[si:], i, j)
if err != nil {
return "", err
}
return s, nil
}
// Parth manages path and error data for processing a single path multiple
// times while error checking only once. Only the first encountered error is
// stored as all subsequent calls to Parth methods that can error are elided.
type Parth struct {
path string
err error
}
// New constructs a pointer to an instance of Parth around the provided path.
func New(path string) *Parth {
return &Parth{path: path}
}
// NewBySpan constructs a pointer to an instance of Parth after preprocessing
// the provided path with Span.
func NewBySpan(path string, i, j int) *Parth {
s, err := Span(path, i, j)
return &Parth{s, err}
}
// NewBySubSpan constructs a pointer to an instance of Parth after
// preprocessing the provided path with SubSpan.
func NewBySubSpan(path, key string, i, j int) *Parth {
s, err := SubSpan(path, key, i, j)
return &Parth{s, err}
}
// Err returns the first error encountered by the *Parth receiver.
func (p *Parth) Err() error {
return p.err
}
// Segment operates the same as the package-level function Segment.
func (p *Parth) Segment(i int, v interface{}) {
if p.err != nil {
return
}
p.err = Segment(p.path, i, v)
}
// Sequent operates the same as the package-level function Sequent.
func (p *Parth) Sequent(key string, v interface{}) {
p.SubSeg(key, 0, v)
}
// Span operates the same as the package-level function Span.
func (p *Parth) Span(i, j int) string {
if p.err != nil {
return ""
}
s, err := Span(p.path, i, j)
p.err = err
return s
}
// SubSeg operates the same as the package-level function SubSeg.
func (p *Parth) SubSeg(key string, i int, v interface{}) {
if p.err != nil {
return
}
p.err = SubSeg(p.path, key, i, v)
}
// SubSpan operates the same as the package-level function SubSpan.
func (p *Parth) SubSpan(key string, i, j int) string {
if p.err != nil {
return ""
}
s, err := SubSpan(p.path, key, i, j)
p.err = err
return s
}
+118
View File
@@ -0,0 +1,118 @@
package parth
func segStartIndexFromStart(path string, seg int) (int, bool) {
if seg < 0 {
return 0, false
}
for n, ct := 0, 0; n < len(path); n++ {
if n > 0 && path[n] == '/' {
ct++
}
if ct == seg {
return n, true
}
}
return 0, false
}
func segStartIndexFromEnd(path string, seg int) (int, bool) {
if seg > -1 {
return 0, false
}
for n, ct := len(path)-1, 0; n >= 0; n-- {
if path[n] == '/' || n == 0 {
ct--
}
if ct == seg {
return n, true
}
}
return 0, false
}
func segEndIndexFromStart(path string, seg int) (int, bool) {
if seg < 1 {
return 0, false
}
for n, ct := 0, 0; n < len(path); n++ {
if path[n] == '/' && n > 0 {
ct++
}
if ct == seg {
return n, true
}
if n+1 == len(path) && ct+1 == seg {
return n + 1, true
}
}
return 0, false
}
func segEndIndexFromEnd(path string, seg int) (int, bool) {
if seg > 0 {
return 0, false
}
if seg == 0 {
return len(path), true
}
if len(path) == 1 && path[0] == '/' {
return 0, true
}
for n, ct := len(path)-1, 0; n >= 0; n-- {
if n == 0 || path[n] == '/' {
ct--
}
if ct == seg {
return n, true
}
}
return 0, false
}
func segIndexByKey(path, key string) (int, bool) { //nolint
if path == "" || key == "" {
return 0, false
}
for n := 0; n < len(path); n++ {
si, ok := segStartIndexFromStart(path, n)
if !ok {
return 0, false
}
if len(path[si:]) == len(key)+1 {
if path[si+1:] == key {
return si, true
}
return 0, false
}
tmpEI, ok := segStartIndexFromStart(path[si:], 1)
if !ok {
return 0, false
}
if path[si+1:tmpEI+si] == key || n == 0 && path[0] != '/' && path[si:tmpEI+si] == key {
return si, true
}
}
return 0, false
}
+305
View File
@@ -0,0 +1,305 @@
package parth
import (
"strconv"
"unicode"
)
func segmentToBool(path string, i int) (bool, error) {
s, err := segmentToString(path, i)
if err != nil {
return false, err
}
v, err := strconv.ParseBool(s)
if err != nil {
return false, ErrDataUnparsable
}
return v, nil
}
func segmentToFloatN(path string, i, size int) (float64, error) {
ss, err := segmentToString(path, i)
if err != nil {
return 0.0, err
}
s, ok := firstFloatFromString(ss)
if !ok {
return 0.0, err
}
v, err := strconv.ParseFloat(s, size)
if err != nil {
return 0.0, ErrDataUnparsable
}
return v, nil
}
func segmentToIntN(path string, i, size int) (int64, error) {
ss, err := segmentToString(path, i)
if err != nil {
return 0, err
}
s, ok := firstIntFromString(ss)
if !ok {
return 0, ErrDataUnparsable
}
v, err := strconv.ParseInt(s, 10, size)
if err != nil {
return 0, ErrDataUnparsable
}
return v, nil
}
func segmentToString(path string, i int) (string, error) {
j := i + 1
if i < 0 {
i--
}
s, err := Span(path, i, j)
if err != nil {
return "", err
}
if s[0] == '/' {
s = s[1:]
}
return s, nil
}
func segmentToUintN(path string, i, size int) (uint64, error) {
ss, err := segmentToString(path, i)
if err != nil {
return 0, err
}
s, ok := firstUintFromString(ss)
if !ok {
return 0, ErrDataUnparsable
}
v, err := strconv.ParseUint(s, 10, size)
if err != nil {
return 0, ErrDataUnparsable
}
return v, nil
}
func subSegToBool(path, key string, i int) (bool, error) {
s, err := subSegToString(path, key, i)
if err != nil {
return false, err
}
v, err := strconv.ParseBool(s)
if err != nil {
return false, ErrDataUnparsable
}
return v, nil
}
func subSegToFloatN(path, key string, i, size int) (float64, error) {
ss, err := subSegToString(path, key, i)
if err != nil {
return 0.0, err
}
s, ok := firstFloatFromString(ss)
if !ok {
return 0.0, ErrDataUnparsable
}
v, err := strconv.ParseFloat(s, size)
if err != nil {
return 0.0, ErrDataUnparsable
}
return v, nil
}
func subSegToIntN(path, key string, i, size int) (int64, error) {
ss, err := subSegToString(path, key, i)
if err != nil {
return 0, err
}
s, ok := firstIntFromString(ss)
if !ok {
return 0, ErrDataUnparsable
}
v, err := strconv.ParseInt(s, 10, size)
if err != nil {
return 0, ErrDataUnparsable
}
return v, nil
}
func subSegToString(path, key string, i int) (string, error) {
ki, ok := segIndexByKey(path, key)
if !ok {
return "", ErrKeySegNotFound
}
i++
s, err := segmentToString(path[ki:], i)
if err != nil {
return "", err
}
return s, nil
}
func subSegToUintN(path, key string, i, size int) (uint64, error) {
ss, err := subSegToString(path, key, i)
if err != nil {
return 0, err
}
s, ok := firstUintFromString(ss)
if !ok {
return 0, ErrDataUnparsable
}
v, err := strconv.ParseUint(s, 10, size)
if err != nil {
return 0, ErrDataUnparsable
}
return v, nil
}
func firstUintFromString(s string) (string, bool) {
ind, l := 0, 0
for n := 0; n < len(s); n++ {
if unicode.IsDigit(rune(s[n])) {
if l == 0 {
ind = n
}
l++
} else {
if l == 0 && s[n] == '.' {
if n+1 < len(s) && unicode.IsDigit(rune(s[n+1])) {
return "0", true
}
break
}
if l > 0 {
break
}
}
}
if l == 0 {
return "", false
}
return s[ind : ind+l], true
}
func firstIntFromString(s string) (string, bool) { //nolint
ind, l := 0, 0
for n := 0; n < len(s); n++ {
if unicode.IsDigit(rune(s[n])) {
if l == 0 {
ind = n
}
l++
} else if s[n] == '-' {
if l == 0 {
ind = n
l++
} else {
break
}
} else {
if l == 0 && s[n] == '.' {
if n+1 < len(s) && unicode.IsDigit(rune(s[n+1])) {
return "0", true
}
break
}
if l > 0 {
break
}
}
}
if l == 0 {
return "", false
}
return s[ind : ind+l], true
}
func firstFloatFromString(s string) (string, bool) { //nolint
c, ind, l := 0, 0, 0
for n := 0; n < len(s); n++ {
if unicode.IsDigit(rune(s[n])) {
if l == 0 {
ind = n
}
l++
} else if s[n] == '-' {
if l == 0 {
ind = n
l++
} else {
break
}
} else if s[n] == '.' {
if l == 0 {
ind = n
}
if c > 0 {
break
}
l++
c++
} else if s[n] == 'e' && l > 0 && n+1 < len(s) && s[n+1] == '+' {
l++
} else if s[n] == '+' && l > 0 && s[n-1] == 'e' {
if n+1 < len(s) && unicode.IsDigit(rune(s[n+1])) {
l++
continue
}
l--
break
} else {
if l > 0 {
break
}
}
}
if l == 0 || s[ind:ind+l] == "." {
return "", false
}
return s[ind : ind+l], true
}