mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 10:51:29 +00:00
Merge pull request #109244 from alexzielenski/clean-third-party-forks
remove unused/orphaned golang package forks
This commit is contained in:
commit
bd6c284583
388
third_party/forked/golang/reflect/deep_equal.go
vendored
388
third_party/forked/golang/reflect/deep_equal.go
vendored
@ -1,388 +0,0 @@
|
|||||||
// Copyright 2009 The Go 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 reflect is a fork of go's standard library reflection package, which
|
|
||||||
// allows for deep equal with equality functions defined.
|
|
||||||
package reflect
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Equalities is a map from type to a function comparing two values of
|
|
||||||
// that type.
|
|
||||||
type Equalities map[reflect.Type]reflect.Value
|
|
||||||
|
|
||||||
// For convenience, panics on errors
|
|
||||||
func EqualitiesOrDie(funcs ...interface{}) Equalities {
|
|
||||||
e := Equalities{}
|
|
||||||
if err := e.AddFuncs(funcs...); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddFuncs is a shortcut for multiple calls to AddFunc.
|
|
||||||
func (e Equalities) AddFuncs(funcs ...interface{}) error {
|
|
||||||
for _, f := range funcs {
|
|
||||||
if err := e.AddFunc(f); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddFunc uses func as an equality function: it must take
|
|
||||||
// two parameters of the same type, and return a boolean.
|
|
||||||
func (e Equalities) AddFunc(eqFunc interface{}) error {
|
|
||||||
fv := reflect.ValueOf(eqFunc)
|
|
||||||
ft := fv.Type()
|
|
||||||
if ft.Kind() != reflect.Func {
|
|
||||||
return fmt.Errorf("expected func, got: %v", ft)
|
|
||||||
}
|
|
||||||
if ft.NumIn() != 2 {
|
|
||||||
return fmt.Errorf("expected two 'in' params, got: %v", ft)
|
|
||||||
}
|
|
||||||
if ft.NumOut() != 1 {
|
|
||||||
return fmt.Errorf("expected one 'out' param, got: %v", ft)
|
|
||||||
}
|
|
||||||
if ft.In(0) != ft.In(1) {
|
|
||||||
return fmt.Errorf("expected arg 1 and 2 to have same type, but got %v", ft)
|
|
||||||
}
|
|
||||||
var forReturnType bool
|
|
||||||
boolType := reflect.TypeOf(forReturnType)
|
|
||||||
if ft.Out(0) != boolType {
|
|
||||||
return fmt.Errorf("expected bool return, got: %v", ft)
|
|
||||||
}
|
|
||||||
e[ft.In(0)] = fv
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Below here is forked from go's reflect/deepequal.go
|
|
||||||
|
|
||||||
// During deepValueEqual, must keep track of checks that are
|
|
||||||
// in progress. The comparison algorithm assumes that all
|
|
||||||
// checks in progress are true when it reencounters them.
|
|
||||||
// Visited comparisons are stored in a map indexed by visit.
|
|
||||||
type visit struct {
|
|
||||||
a1 uintptr
|
|
||||||
a2 uintptr
|
|
||||||
typ reflect.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
// unexportedTypePanic is thrown when you use this DeepEqual on something that has an
|
|
||||||
// unexported type. It indicates a programmer error, so should not occur at runtime,
|
|
||||||
// which is why it's not public and thus impossible to catch.
|
|
||||||
type unexportedTypePanic []reflect.Type
|
|
||||||
|
|
||||||
func (u unexportedTypePanic) Error() string { return u.String() }
|
|
||||||
func (u unexportedTypePanic) String() string {
|
|
||||||
strs := make([]string, len(u))
|
|
||||||
for i, t := range u {
|
|
||||||
strs[i] = fmt.Sprintf("%v", t)
|
|
||||||
}
|
|
||||||
return "an unexported field was encountered, nested like this: " + strings.Join(strs, " -> ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeUsefulPanic(v reflect.Value) {
|
|
||||||
if x := recover(); x != nil {
|
|
||||||
if u, ok := x.(unexportedTypePanic); ok {
|
|
||||||
u = append(unexportedTypePanic{v.Type()}, u...)
|
|
||||||
x = u
|
|
||||||
}
|
|
||||||
panic(x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tests for deep equality using reflected types. The map argument tracks
|
|
||||||
// comparisons that have already been seen, which allows short circuiting on
|
|
||||||
// recursive types.
|
|
||||||
func (e Equalities) deepValueEqual(v1, v2 reflect.Value, visited map[visit]bool, depth int) bool {
|
|
||||||
defer makeUsefulPanic(v1)
|
|
||||||
|
|
||||||
if !v1.IsValid() || !v2.IsValid() {
|
|
||||||
return v1.IsValid() == v2.IsValid()
|
|
||||||
}
|
|
||||||
if v1.Type() != v2.Type() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if fv, ok := e[v1.Type()]; ok {
|
|
||||||
return fv.Call([]reflect.Value{v1, v2})[0].Bool()
|
|
||||||
}
|
|
||||||
|
|
||||||
hard := func(k reflect.Kind) bool {
|
|
||||||
switch k {
|
|
||||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.Struct:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if v1.CanAddr() && v2.CanAddr() && hard(v1.Kind()) {
|
|
||||||
addr1 := v1.UnsafeAddr()
|
|
||||||
addr2 := v2.UnsafeAddr()
|
|
||||||
if addr1 > addr2 {
|
|
||||||
// Canonicalize order to reduce number of entries in visited.
|
|
||||||
addr1, addr2 = addr2, addr1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Short circuit if references are identical ...
|
|
||||||
if addr1 == addr2 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... or already seen
|
|
||||||
typ := v1.Type()
|
|
||||||
v := visit{addr1, addr2, typ}
|
|
||||||
if visited[v] {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remember for later.
|
|
||||||
visited[v] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch v1.Kind() {
|
|
||||||
case reflect.Array:
|
|
||||||
// We don't need to check length here because length is part of
|
|
||||||
// an array's type, which has already been filtered for.
|
|
||||||
for i := 0; i < v1.Len(); i++ {
|
|
||||||
if !e.deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
case reflect.Slice:
|
|
||||||
if (v1.IsNil() || v1.Len() == 0) != (v2.IsNil() || v2.Len() == 0) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if v1.IsNil() || v1.Len() == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if v1.Len() != v2.Len() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if v1.Pointer() == v2.Pointer() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for i := 0; i < v1.Len(); i++ {
|
|
||||||
if !e.deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
case reflect.Interface:
|
|
||||||
if v1.IsNil() || v2.IsNil() {
|
|
||||||
return v1.IsNil() == v2.IsNil()
|
|
||||||
}
|
|
||||||
return e.deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
|
|
||||||
case reflect.Ptr:
|
|
||||||
return e.deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
|
|
||||||
case reflect.Struct:
|
|
||||||
for i, n := 0, v1.NumField(); i < n; i++ {
|
|
||||||
if !e.deepValueEqual(v1.Field(i), v2.Field(i), visited, depth+1) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
case reflect.Map:
|
|
||||||
if (v1.IsNil() || v1.Len() == 0) != (v2.IsNil() || v2.Len() == 0) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if v1.IsNil() || v1.Len() == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if v1.Len() != v2.Len() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if v1.Pointer() == v2.Pointer() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for _, k := range v1.MapKeys() {
|
|
||||||
if !e.deepValueEqual(v1.MapIndex(k), v2.MapIndex(k), visited, depth+1) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
case reflect.Func:
|
|
||||||
if v1.IsNil() && v2.IsNil() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// Can't do better than this:
|
|
||||||
return false
|
|
||||||
default:
|
|
||||||
// Normal equality suffices
|
|
||||||
if !v1.CanInterface() || !v2.CanInterface() {
|
|
||||||
panic(unexportedTypePanic{})
|
|
||||||
}
|
|
||||||
return v1.Interface() == v2.Interface()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepEqual is like reflect.DeepEqual, but focused on semantic equality
|
|
||||||
// instead of memory equality.
|
|
||||||
//
|
|
||||||
// It will use e's equality functions if it finds types that match.
|
|
||||||
//
|
|
||||||
// An empty slice *is* equal to a nil slice for our purposes; same for maps.
|
|
||||||
//
|
|
||||||
// Unexported field members cannot be compared and will cause an informative panic; you must add an Equality
|
|
||||||
// function for these types.
|
|
||||||
func (e Equalities) DeepEqual(a1, a2 interface{}) bool {
|
|
||||||
if a1 == nil || a2 == nil {
|
|
||||||
return a1 == a2
|
|
||||||
}
|
|
||||||
v1 := reflect.ValueOf(a1)
|
|
||||||
v2 := reflect.ValueOf(a2)
|
|
||||||
if v1.Type() != v2.Type() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return e.deepValueEqual(v1, v2, make(map[visit]bool), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e Equalities) deepValueDerive(v1, v2 reflect.Value, visited map[visit]bool, depth int) bool {
|
|
||||||
defer makeUsefulPanic(v1)
|
|
||||||
|
|
||||||
if !v1.IsValid() || !v2.IsValid() {
|
|
||||||
return v1.IsValid() == v2.IsValid()
|
|
||||||
}
|
|
||||||
if v1.Type() != v2.Type() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if fv, ok := e[v1.Type()]; ok {
|
|
||||||
return fv.Call([]reflect.Value{v1, v2})[0].Bool()
|
|
||||||
}
|
|
||||||
|
|
||||||
hard := func(k reflect.Kind) bool {
|
|
||||||
switch k {
|
|
||||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.Struct:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if v1.CanAddr() && v2.CanAddr() && hard(v1.Kind()) {
|
|
||||||
addr1 := v1.UnsafeAddr()
|
|
||||||
addr2 := v2.UnsafeAddr()
|
|
||||||
if addr1 > addr2 {
|
|
||||||
// Canonicalize order to reduce number of entries in visited.
|
|
||||||
addr1, addr2 = addr2, addr1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Short circuit if references are identical ...
|
|
||||||
if addr1 == addr2 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... or already seen
|
|
||||||
typ := v1.Type()
|
|
||||||
v := visit{addr1, addr2, typ}
|
|
||||||
if visited[v] {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remember for later.
|
|
||||||
visited[v] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
switch v1.Kind() {
|
|
||||||
case reflect.Array:
|
|
||||||
// We don't need to check length here because length is part of
|
|
||||||
// an array's type, which has already been filtered for.
|
|
||||||
for i := 0; i < v1.Len(); i++ {
|
|
||||||
if !e.deepValueDerive(v1.Index(i), v2.Index(i), visited, depth+1) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
case reflect.Slice:
|
|
||||||
if v1.IsNil() || v1.Len() == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if v1.Len() > v2.Len() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if v1.Pointer() == v2.Pointer() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for i := 0; i < v1.Len(); i++ {
|
|
||||||
if !e.deepValueDerive(v1.Index(i), v2.Index(i), visited, depth+1) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
case reflect.String:
|
|
||||||
if v1.Len() == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if v1.Len() > v2.Len() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return v1.String() == v2.String()
|
|
||||||
case reflect.Interface:
|
|
||||||
if v1.IsNil() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return e.deepValueDerive(v1.Elem(), v2.Elem(), visited, depth+1)
|
|
||||||
case reflect.Ptr:
|
|
||||||
if v1.IsNil() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return e.deepValueDerive(v1.Elem(), v2.Elem(), visited, depth+1)
|
|
||||||
case reflect.Struct:
|
|
||||||
for i, n := 0, v1.NumField(); i < n; i++ {
|
|
||||||
if !e.deepValueDerive(v1.Field(i), v2.Field(i), visited, depth+1) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
case reflect.Map:
|
|
||||||
if v1.IsNil() || v1.Len() == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if v1.Len() > v2.Len() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if v1.Pointer() == v2.Pointer() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for _, k := range v1.MapKeys() {
|
|
||||||
if !e.deepValueDerive(v1.MapIndex(k), v2.MapIndex(k), visited, depth+1) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
case reflect.Func:
|
|
||||||
if v1.IsNil() && v2.IsNil() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// Can't do better than this:
|
|
||||||
return false
|
|
||||||
default:
|
|
||||||
// Normal equality suffices
|
|
||||||
if !v1.CanInterface() || !v2.CanInterface() {
|
|
||||||
panic(unexportedTypePanic{})
|
|
||||||
}
|
|
||||||
return v1.Interface() == v2.Interface()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepDerivative is similar to DeepEqual except that unset fields in a1 are
|
|
||||||
// ignored (not compared). This allows us to focus on the fields that matter to
|
|
||||||
// the semantic comparison.
|
|
||||||
//
|
|
||||||
// The unset fields include a nil pointer and an empty string.
|
|
||||||
func (e Equalities) DeepDerivative(a1, a2 interface{}) bool {
|
|
||||||
if a1 == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
v1 := reflect.ValueOf(a1)
|
|
||||||
v2 := reflect.ValueOf(a2)
|
|
||||||
if v1.Type() != v2.Type() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return e.deepValueDerive(v1, v2, make(map[visit]bool), 0)
|
|
||||||
}
|
|
137
third_party/forked/golang/reflect/deep_equal_test.go
vendored
137
third_party/forked/golang/reflect/deep_equal_test.go
vendored
@ -1,137 +0,0 @@
|
|||||||
// Copyright 2009 The Go 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 reflect
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEqualities(t *testing.T) {
|
|
||||||
e := Equalities{}
|
|
||||||
type Bar struct {
|
|
||||||
X int
|
|
||||||
}
|
|
||||||
type Baz struct {
|
|
||||||
Y Bar
|
|
||||||
}
|
|
||||||
err := e.AddFuncs(
|
|
||||||
func(a, b int) bool {
|
|
||||||
return a+1 == b
|
|
||||||
},
|
|
||||||
func(a, b Bar) bool {
|
|
||||||
return a.X*10 == b.X
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Foo struct {
|
|
||||||
X int
|
|
||||||
}
|
|
||||||
|
|
||||||
table := []struct {
|
|
||||||
a, b interface{}
|
|
||||||
equal bool
|
|
||||||
}{
|
|
||||||
{1, 2, true},
|
|
||||||
{2, 1, false},
|
|
||||||
{"foo", "fo", false},
|
|
||||||
{"foo", "foo", true},
|
|
||||||
{"foo", "foobar", false},
|
|
||||||
{Foo{1}, Foo{2}, true},
|
|
||||||
{Foo{2}, Foo{1}, false},
|
|
||||||
{Bar{1}, Bar{10}, true},
|
|
||||||
{&Bar{1}, &Bar{10}, true},
|
|
||||||
{Baz{Bar{1}}, Baz{Bar{10}}, true},
|
|
||||||
{[...]string{}, [...]string{"1", "2", "3"}, false},
|
|
||||||
{[...]string{"1"}, [...]string{"1", "2", "3"}, false},
|
|
||||||
{[...]string{"1", "2", "3"}, [...]string{}, false},
|
|
||||||
{[...]string{"1", "2", "3"}, [...]string{"1", "2", "3"}, true},
|
|
||||||
{map[string]int{"foo": 1}, map[string]int{}, false},
|
|
||||||
{map[string]int{"foo": 1}, map[string]int{"foo": 2}, true},
|
|
||||||
{map[string]int{"foo": 2}, map[string]int{"foo": 1}, false},
|
|
||||||
{map[string]int{"foo": 1}, map[string]int{"foo": 2, "bar": 6}, false},
|
|
||||||
{map[string]int{"foo": 1, "bar": 6}, map[string]int{"foo": 2}, false},
|
|
||||||
{map[string]int{}, map[string]int(nil), true},
|
|
||||||
{[]string(nil), []string(nil), true},
|
|
||||||
{[]string{}, []string(nil), true},
|
|
||||||
{[]string(nil), []string{}, true},
|
|
||||||
{[]string{"1"}, []string(nil), false},
|
|
||||||
{[]string{}, []string{"1", "2", "3"}, false},
|
|
||||||
{[]string{"1"}, []string{"1", "2", "3"}, false},
|
|
||||||
{[]string{"1", "2", "3"}, []string{}, false},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, item := range table {
|
|
||||||
if e, a := item.equal, e.DeepEqual(item.a, item.b); e != a {
|
|
||||||
t.Errorf("Expected (%+v == %+v) == %v, but got %v", item.a, item.b, e, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDerivates(t *testing.T) {
|
|
||||||
e := Equalities{}
|
|
||||||
type Bar struct {
|
|
||||||
X int
|
|
||||||
}
|
|
||||||
type Baz struct {
|
|
||||||
Y Bar
|
|
||||||
}
|
|
||||||
err := e.AddFuncs(
|
|
||||||
func(a, b int) bool {
|
|
||||||
return a+1 == b
|
|
||||||
},
|
|
||||||
func(a, b Bar) bool {
|
|
||||||
return a.X*10 == b.X
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Foo struct {
|
|
||||||
X int
|
|
||||||
}
|
|
||||||
|
|
||||||
table := []struct {
|
|
||||||
a, b interface{}
|
|
||||||
equal bool
|
|
||||||
}{
|
|
||||||
{1, 2, true},
|
|
||||||
{2, 1, false},
|
|
||||||
{"foo", "fo", false},
|
|
||||||
{"foo", "foo", true},
|
|
||||||
{"foo", "foobar", false},
|
|
||||||
{Foo{1}, Foo{2}, true},
|
|
||||||
{Foo{2}, Foo{1}, false},
|
|
||||||
{Bar{1}, Bar{10}, true},
|
|
||||||
{&Bar{1}, &Bar{10}, true},
|
|
||||||
{Baz{Bar{1}}, Baz{Bar{10}}, true},
|
|
||||||
{[...]string{}, [...]string{"1", "2", "3"}, false},
|
|
||||||
{[...]string{"1"}, [...]string{"1", "2", "3"}, false},
|
|
||||||
{[...]string{"1", "2", "3"}, [...]string{}, false},
|
|
||||||
{[...]string{"1", "2", "3"}, [...]string{"1", "2", "3"}, true},
|
|
||||||
{map[string]int{"foo": 1}, map[string]int{}, false},
|
|
||||||
{map[string]int{"foo": 1}, map[string]int{"foo": 2}, true},
|
|
||||||
{map[string]int{"foo": 2}, map[string]int{"foo": 1}, false},
|
|
||||||
{map[string]int{"foo": 1}, map[string]int{"foo": 2, "bar": 6}, true},
|
|
||||||
{map[string]int{"foo": 1, "bar": 6}, map[string]int{"foo": 2}, false},
|
|
||||||
{map[string]int{}, map[string]int(nil), true},
|
|
||||||
{[]string(nil), []string(nil), true},
|
|
||||||
{[]string{}, []string(nil), true},
|
|
||||||
{[]string(nil), []string{}, true},
|
|
||||||
{[]string{"1"}, []string(nil), false},
|
|
||||||
{[]string{}, []string{"1", "2", "3"}, true},
|
|
||||||
{[]string{"1"}, []string{"1", "2", "3"}, true},
|
|
||||||
{[]string{"1", "2", "3"}, []string{}, false},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, item := range table {
|
|
||||||
if e, a := item.equal, e.DeepDerivative(item.a, item.b); e != a {
|
|
||||||
t.Errorf("Expected (%+v ~ %+v) == %v, but got %v", item.a, item.b, e, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
91
third_party/forked/golang/reflect/type.go
vendored
91
third_party/forked/golang/reflect/type.go
vendored
@ -1,91 +0,0 @@
|
|||||||
//This package is copied from Go library reflect/type.go.
|
|
||||||
//The struct tag library provides no way to extract the list of struct tags, only
|
|
||||||
//a specific tag
|
|
||||||
package reflect
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type StructTag struct {
|
|
||||||
Name string
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t StructTag) String() string {
|
|
||||||
return fmt.Sprintf("%s:%q", t.Name, t.Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
type StructTags []StructTag
|
|
||||||
|
|
||||||
func (tags StructTags) String() string {
|
|
||||||
s := make([]string, 0, len(tags))
|
|
||||||
for _, tag := range tags {
|
|
||||||
s = append(s, tag.String())
|
|
||||||
}
|
|
||||||
return "`" + strings.Join(s, " ") + "`"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tags StructTags) Has(name string) bool {
|
|
||||||
for i := range tags {
|
|
||||||
if tags[i].Name == name {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseStructTags returns the full set of fields in a struct tag in the order they appear in
|
|
||||||
// the struct tag.
|
|
||||||
func ParseStructTags(tag string) (StructTags, error) {
|
|
||||||
tags := StructTags{}
|
|
||||||
for tag != "" {
|
|
||||||
// Skip leading space.
|
|
||||||
i := 0
|
|
||||||
for i < len(tag) && tag[i] == ' ' {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
tag = tag[i:]
|
|
||||||
if tag == "" {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scan to colon. A space, a quote or a control character is a syntax error.
|
|
||||||
// Strictly speaking, control chars include the range [0x7f, 0x9f], not just
|
|
||||||
// [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
|
|
||||||
// as it is simpler to inspect the tag's bytes than the tag's runes.
|
|
||||||
i = 0
|
|
||||||
for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
name := string(tag[:i])
|
|
||||||
tag = tag[i+1:]
|
|
||||||
|
|
||||||
// Scan quoted string to find value.
|
|
||||||
i = 1
|
|
||||||
for i < len(tag) && tag[i] != '"' {
|
|
||||||
if tag[i] == '\\' {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if i >= len(tag) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
qvalue := string(tag[:i+1])
|
|
||||||
tag = tag[i+1:]
|
|
||||||
|
|
||||||
value, err := strconv.Unquote(qvalue)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
tags = append(tags, StructTag{Name: name, Value: value})
|
|
||||||
}
|
|
||||||
return tags, nil
|
|
||||||
}
|
|
94
third_party/forked/golang/template/exec.go
vendored
94
third_party/forked/golang/template/exec.go
vendored
@ -1,94 +0,0 @@
|
|||||||
//This package is copied from Go library text/template.
|
|
||||||
//The original private functions indirect and printableValue
|
|
||||||
//are exported as public functions.
|
|
||||||
package template
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
var Indirect = indirect
|
|
||||||
var PrintableValue = printableValue
|
|
||||||
|
|
||||||
var (
|
|
||||||
errorType = reflect.TypeOf((*error)(nil)).Elem()
|
|
||||||
fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
|
|
||||||
)
|
|
||||||
|
|
||||||
// indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
|
|
||||||
// We indirect through pointers and empty interfaces (only) because
|
|
||||||
// non-empty interfaces have methods we might need.
|
|
||||||
func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
|
|
||||||
for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
|
|
||||||
if v.IsNil() {
|
|
||||||
return v, true
|
|
||||||
}
|
|
||||||
if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// printableValue returns the, possibly indirected, interface value inside v that
|
|
||||||
// is best for a call to formatted printer.
|
|
||||||
func printableValue(v reflect.Value) (interface{}, bool) {
|
|
||||||
if v.Kind() == reflect.Ptr {
|
|
||||||
v, _ = indirect(v) // fmt.Fprint handles nil.
|
|
||||||
}
|
|
||||||
if !v.IsValid() {
|
|
||||||
return "<no value>", true
|
|
||||||
}
|
|
||||||
|
|
||||||
if !v.Type().Implements(errorType) && !v.Type().Implements(fmtStringerType) {
|
|
||||||
if v.CanAddr() && (reflect.PtrTo(v.Type()).Implements(errorType) || reflect.PtrTo(v.Type()).Implements(fmtStringerType)) {
|
|
||||||
v = v.Addr()
|
|
||||||
} else {
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Chan, reflect.Func:
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v.Interface(), true
|
|
||||||
}
|
|
||||||
|
|
||||||
// canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero.
|
|
||||||
func canBeNil(typ reflect.Type) bool {
|
|
||||||
switch typ.Kind() {
|
|
||||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// isTrue reports whether the value is 'true', in the sense of not the zero of its type,
|
|
||||||
// and whether the value has a meaningful truth value.
|
|
||||||
func isTrue(val reflect.Value) (truth, ok bool) {
|
|
||||||
if !val.IsValid() {
|
|
||||||
// Something like var x interface{}, never set. It's a form of nil.
|
|
||||||
return false, true
|
|
||||||
}
|
|
||||||
switch val.Kind() {
|
|
||||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
|
||||||
truth = val.Len() > 0
|
|
||||||
case reflect.Bool:
|
|
||||||
truth = val.Bool()
|
|
||||||
case reflect.Complex64, reflect.Complex128:
|
|
||||||
truth = val.Complex() != 0
|
|
||||||
case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Interface:
|
|
||||||
truth = !val.IsNil()
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
truth = val.Int() != 0
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
truth = val.Float() != 0
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
||||||
truth = val.Uint() != 0
|
|
||||||
case reflect.Struct:
|
|
||||||
truth = true // Struct values are always true.
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return truth, true
|
|
||||||
}
|
|
599
third_party/forked/golang/template/funcs.go
vendored
599
third_party/forked/golang/template/funcs.go
vendored
@ -1,599 +0,0 @@
|
|||||||
//This package is copied from Go library text/template.
|
|
||||||
//The original private functions eq, ge, gt, le, lt, and ne
|
|
||||||
//are exported as public functions.
|
|
||||||
package template
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/url"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
var Equal = eq
|
|
||||||
var GreaterEqual = ge
|
|
||||||
var Greater = gt
|
|
||||||
var LessEqual = le
|
|
||||||
var Less = lt
|
|
||||||
var NotEqual = ne
|
|
||||||
|
|
||||||
// FuncMap is the type of the map defining the mapping from names to functions.
|
|
||||||
// Each function must have either a single return value, or two return values of
|
|
||||||
// which the second has type error. In that case, if the second (error)
|
|
||||||
// return value evaluates to non-nil during execution, execution terminates and
|
|
||||||
// Execute returns that error.
|
|
||||||
type FuncMap map[string]interface{}
|
|
||||||
|
|
||||||
var builtins = FuncMap{
|
|
||||||
"and": and,
|
|
||||||
"call": call,
|
|
||||||
"html": HTMLEscaper,
|
|
||||||
"index": index,
|
|
||||||
"js": JSEscaper,
|
|
||||||
"len": length,
|
|
||||||
"not": not,
|
|
||||||
"or": or,
|
|
||||||
"print": fmt.Sprint,
|
|
||||||
"printf": fmt.Sprintf,
|
|
||||||
"println": fmt.Sprintln,
|
|
||||||
"urlquery": URLQueryEscaper,
|
|
||||||
|
|
||||||
// Comparisons
|
|
||||||
"eq": eq, // ==
|
|
||||||
"ge": ge, // >=
|
|
||||||
"gt": gt, // >
|
|
||||||
"le": le, // <=
|
|
||||||
"lt": lt, // <
|
|
||||||
"ne": ne, // !=
|
|
||||||
}
|
|
||||||
|
|
||||||
var builtinFuncs = createValueFuncs(builtins)
|
|
||||||
|
|
||||||
// createValueFuncs turns a FuncMap into a map[string]reflect.Value
|
|
||||||
func createValueFuncs(funcMap FuncMap) map[string]reflect.Value {
|
|
||||||
m := make(map[string]reflect.Value)
|
|
||||||
addValueFuncs(m, funcMap)
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
// addValueFuncs adds to values the functions in funcs, converting them to reflect.Values.
|
|
||||||
func addValueFuncs(out map[string]reflect.Value, in FuncMap) {
|
|
||||||
for name, fn := range in {
|
|
||||||
v := reflect.ValueOf(fn)
|
|
||||||
if v.Kind() != reflect.Func {
|
|
||||||
panic("value for " + name + " not a function")
|
|
||||||
}
|
|
||||||
if !goodFunc(v.Type()) {
|
|
||||||
panic(fmt.Errorf("can't install method/function %q with %d results", name, v.Type().NumOut()))
|
|
||||||
}
|
|
||||||
out[name] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddFuncs adds to values the functions in funcs. It does no checking of the input -
|
|
||||||
// call addValueFuncs first.
|
|
||||||
func addFuncs(out, in FuncMap) {
|
|
||||||
for name, fn := range in {
|
|
||||||
out[name] = fn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// goodFunc checks that the function or method has the right result signature.
|
|
||||||
func goodFunc(typ reflect.Type) bool {
|
|
||||||
// We allow functions with 1 result or 2 results where the second is an error.
|
|
||||||
switch {
|
|
||||||
case typ.NumOut() == 1:
|
|
||||||
return true
|
|
||||||
case typ.NumOut() == 2 && typ.Out(1) == errorType:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// findFunction looks for a function in the template, and global map.
|
|
||||||
func findFunction(name string) (reflect.Value, bool) {
|
|
||||||
if fn := builtinFuncs[name]; fn.IsValid() {
|
|
||||||
return fn, true
|
|
||||||
}
|
|
||||||
return reflect.Value{}, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Indexing.
|
|
||||||
|
|
||||||
// index returns the result of indexing its first argument by the following
|
|
||||||
// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
|
|
||||||
// indexed item must be a map, slice, or array.
|
|
||||||
func index(item interface{}, indices ...interface{}) (interface{}, error) {
|
|
||||||
v := reflect.ValueOf(item)
|
|
||||||
for _, i := range indices {
|
|
||||||
index := reflect.ValueOf(i)
|
|
||||||
var isNil bool
|
|
||||||
if v, isNil = indirect(v); isNil {
|
|
||||||
return nil, fmt.Errorf("index of nil pointer")
|
|
||||||
}
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Array, reflect.Slice, reflect.String:
|
|
||||||
var x int64
|
|
||||||
switch index.Kind() {
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
x = index.Int()
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
||||||
x = int64(index.Uint())
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type())
|
|
||||||
}
|
|
||||||
if x < 0 || x >= int64(v.Len()) {
|
|
||||||
return nil, fmt.Errorf("index out of range: %d", x)
|
|
||||||
}
|
|
||||||
v = v.Index(int(x))
|
|
||||||
case reflect.Map:
|
|
||||||
if !index.IsValid() {
|
|
||||||
index = reflect.Zero(v.Type().Key())
|
|
||||||
}
|
|
||||||
if !index.Type().AssignableTo(v.Type().Key()) {
|
|
||||||
return nil, fmt.Errorf("%s is not index type for %s", index.Type(), v.Type())
|
|
||||||
}
|
|
||||||
if x := v.MapIndex(index); x.IsValid() {
|
|
||||||
v = x
|
|
||||||
} else {
|
|
||||||
v = reflect.Zero(v.Type().Elem())
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("can't index item of type %s", v.Type())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v.Interface(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Length
|
|
||||||
|
|
||||||
// length returns the length of the item, with an error if it has no defined length.
|
|
||||||
func length(item interface{}) (int, error) {
|
|
||||||
v, isNil := indirect(reflect.ValueOf(item))
|
|
||||||
if isNil {
|
|
||||||
return 0, fmt.Errorf("len of nil pointer")
|
|
||||||
}
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
|
|
||||||
return v.Len(), nil
|
|
||||||
}
|
|
||||||
return 0, fmt.Errorf("len of type %s", v.Type())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function invocation
|
|
||||||
|
|
||||||
// call returns the result of evaluating the first argument as a function.
|
|
||||||
// The function must return 1 result, or 2 results, the second of which is an error.
|
|
||||||
func call(fn interface{}, args ...interface{}) (interface{}, error) {
|
|
||||||
v := reflect.ValueOf(fn)
|
|
||||||
typ := v.Type()
|
|
||||||
if typ.Kind() != reflect.Func {
|
|
||||||
return nil, fmt.Errorf("non-function of type %s", typ)
|
|
||||||
}
|
|
||||||
if !goodFunc(typ) {
|
|
||||||
return nil, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut())
|
|
||||||
}
|
|
||||||
numIn := typ.NumIn()
|
|
||||||
var dddType reflect.Type
|
|
||||||
if typ.IsVariadic() {
|
|
||||||
if len(args) < numIn-1 {
|
|
||||||
return nil, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1)
|
|
||||||
}
|
|
||||||
dddType = typ.In(numIn - 1).Elem()
|
|
||||||
} else {
|
|
||||||
if len(args) != numIn {
|
|
||||||
return nil, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
argv := make([]reflect.Value, len(args))
|
|
||||||
for i, arg := range args {
|
|
||||||
value := reflect.ValueOf(arg)
|
|
||||||
// Compute the expected type. Clumsy because of variadics.
|
|
||||||
var argType reflect.Type
|
|
||||||
if !typ.IsVariadic() || i < numIn-1 {
|
|
||||||
argType = typ.In(i)
|
|
||||||
} else {
|
|
||||||
argType = dddType
|
|
||||||
}
|
|
||||||
if !value.IsValid() && canBeNil(argType) {
|
|
||||||
value = reflect.Zero(argType)
|
|
||||||
}
|
|
||||||
if !value.Type().AssignableTo(argType) {
|
|
||||||
return nil, fmt.Errorf("arg %d has type %s; should be %s", i, value.Type(), argType)
|
|
||||||
}
|
|
||||||
argv[i] = value
|
|
||||||
}
|
|
||||||
result := v.Call(argv)
|
|
||||||
if len(result) == 2 && !result[1].IsNil() {
|
|
||||||
return result[0].Interface(), result[1].Interface().(error)
|
|
||||||
}
|
|
||||||
return result[0].Interface(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Boolean logic.
|
|
||||||
|
|
||||||
func truth(a interface{}) bool {
|
|
||||||
t, _ := isTrue(reflect.ValueOf(a))
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// and computes the Boolean AND of its arguments, returning
|
|
||||||
// the first false argument it encounters, or the last argument.
|
|
||||||
func and(arg0 interface{}, args ...interface{}) interface{} {
|
|
||||||
if !truth(arg0) {
|
|
||||||
return arg0
|
|
||||||
}
|
|
||||||
for i := range args {
|
|
||||||
arg0 = args[i]
|
|
||||||
if !truth(arg0) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return arg0
|
|
||||||
}
|
|
||||||
|
|
||||||
// or computes the Boolean OR of its arguments, returning
|
|
||||||
// the first true argument it encounters, or the last argument.
|
|
||||||
func or(arg0 interface{}, args ...interface{}) interface{} {
|
|
||||||
if truth(arg0) {
|
|
||||||
return arg0
|
|
||||||
}
|
|
||||||
for i := range args {
|
|
||||||
arg0 = args[i]
|
|
||||||
if truth(arg0) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return arg0
|
|
||||||
}
|
|
||||||
|
|
||||||
// not returns the Boolean negation of its argument.
|
|
||||||
func not(arg interface{}) (truth bool) {
|
|
||||||
truth, _ = isTrue(reflect.ValueOf(arg))
|
|
||||||
return !truth
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comparison.
|
|
||||||
|
|
||||||
// TODO: Perhaps allow comparison between signed and unsigned integers.
|
|
||||||
|
|
||||||
var (
|
|
||||||
errBadComparisonType = errors.New("invalid type for comparison")
|
|
||||||
errBadComparison = errors.New("incompatible types for comparison")
|
|
||||||
errNoComparison = errors.New("missing argument for comparison")
|
|
||||||
)
|
|
||||||
|
|
||||||
type kind int
|
|
||||||
|
|
||||||
const (
|
|
||||||
invalidKind kind = iota
|
|
||||||
boolKind
|
|
||||||
complexKind
|
|
||||||
intKind
|
|
||||||
floatKind
|
|
||||||
integerKind
|
|
||||||
stringKind
|
|
||||||
uintKind
|
|
||||||
)
|
|
||||||
|
|
||||||
func basicKind(v reflect.Value) (kind, error) {
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Bool:
|
|
||||||
return boolKind, nil
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
return intKind, nil
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
||||||
return uintKind, nil
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
return floatKind, nil
|
|
||||||
case reflect.Complex64, reflect.Complex128:
|
|
||||||
return complexKind, nil
|
|
||||||
case reflect.String:
|
|
||||||
return stringKind, nil
|
|
||||||
}
|
|
||||||
return invalidKind, errBadComparisonType
|
|
||||||
}
|
|
||||||
|
|
||||||
// eq evaluates the comparison a == b || a == c || ...
|
|
||||||
func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
|
|
||||||
v1 := reflect.ValueOf(arg1)
|
|
||||||
k1, err := basicKind(v1)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if len(arg2) == 0 {
|
|
||||||
return false, errNoComparison
|
|
||||||
}
|
|
||||||
for _, arg := range arg2 {
|
|
||||||
v2 := reflect.ValueOf(arg)
|
|
||||||
k2, err := basicKind(v2)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
truth := false
|
|
||||||
if k1 != k2 {
|
|
||||||
// Special case: Can compare integer values regardless of type's sign.
|
|
||||||
switch {
|
|
||||||
case k1 == intKind && k2 == uintKind:
|
|
||||||
truth = v1.Int() >= 0 && uint64(v1.Int()) == v2.Uint()
|
|
||||||
case k1 == uintKind && k2 == intKind:
|
|
||||||
truth = v2.Int() >= 0 && v1.Uint() == uint64(v2.Int())
|
|
||||||
default:
|
|
||||||
return false, errBadComparison
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch k1 {
|
|
||||||
case boolKind:
|
|
||||||
truth = v1.Bool() == v2.Bool()
|
|
||||||
case complexKind:
|
|
||||||
truth = v1.Complex() == v2.Complex()
|
|
||||||
case floatKind:
|
|
||||||
truth = v1.Float() == v2.Float()
|
|
||||||
case intKind:
|
|
||||||
truth = v1.Int() == v2.Int()
|
|
||||||
case stringKind:
|
|
||||||
truth = v1.String() == v2.String()
|
|
||||||
case uintKind:
|
|
||||||
truth = v1.Uint() == v2.Uint()
|
|
||||||
default:
|
|
||||||
panic("invalid kind")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if truth {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ne evaluates the comparison a != b.
|
|
||||||
func ne(arg1, arg2 interface{}) (bool, error) {
|
|
||||||
// != is the inverse of ==.
|
|
||||||
equal, err := eq(arg1, arg2)
|
|
||||||
return !equal, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// lt evaluates the comparison a < b.
|
|
||||||
func lt(arg1, arg2 interface{}) (bool, error) {
|
|
||||||
v1 := reflect.ValueOf(arg1)
|
|
||||||
k1, err := basicKind(v1)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
v2 := reflect.ValueOf(arg2)
|
|
||||||
k2, err := basicKind(v2)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
truth := false
|
|
||||||
if k1 != k2 {
|
|
||||||
// Special case: Can compare integer values regardless of type's sign.
|
|
||||||
switch {
|
|
||||||
case k1 == intKind && k2 == uintKind:
|
|
||||||
truth = v1.Int() < 0 || uint64(v1.Int()) < v2.Uint()
|
|
||||||
case k1 == uintKind && k2 == intKind:
|
|
||||||
truth = v2.Int() >= 0 && v1.Uint() < uint64(v2.Int())
|
|
||||||
default:
|
|
||||||
return false, errBadComparison
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch k1 {
|
|
||||||
case boolKind, complexKind:
|
|
||||||
return false, errBadComparisonType
|
|
||||||
case floatKind:
|
|
||||||
truth = v1.Float() < v2.Float()
|
|
||||||
case intKind:
|
|
||||||
truth = v1.Int() < v2.Int()
|
|
||||||
case stringKind:
|
|
||||||
truth = v1.String() < v2.String()
|
|
||||||
case uintKind:
|
|
||||||
truth = v1.Uint() < v2.Uint()
|
|
||||||
default:
|
|
||||||
panic("invalid kind")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return truth, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// le evaluates the comparison <= b.
|
|
||||||
func le(arg1, arg2 interface{}) (bool, error) {
|
|
||||||
// <= is < or ==.
|
|
||||||
lessThan, err := lt(arg1, arg2)
|
|
||||||
if lessThan || err != nil {
|
|
||||||
return lessThan, err
|
|
||||||
}
|
|
||||||
return eq(arg1, arg2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// gt evaluates the comparison a > b.
|
|
||||||
func gt(arg1, arg2 interface{}) (bool, error) {
|
|
||||||
// > is the inverse of <=.
|
|
||||||
lessOrEqual, err := le(arg1, arg2)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return !lessOrEqual, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ge evaluates the comparison a >= b.
|
|
||||||
func ge(arg1, arg2 interface{}) (bool, error) {
|
|
||||||
// >= is the inverse of <.
|
|
||||||
lessThan, err := lt(arg1, arg2)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return !lessThan, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTML escaping.
|
|
||||||
|
|
||||||
var (
|
|
||||||
htmlQuot = []byte(""") // shorter than """
|
|
||||||
htmlApos = []byte("'") // shorter than "'" and apos was not in HTML until HTML5
|
|
||||||
htmlAmp = []byte("&")
|
|
||||||
htmlLt = []byte("<")
|
|
||||||
htmlGt = []byte(">")
|
|
||||||
)
|
|
||||||
|
|
||||||
// HTMLEscape writes to w the escaped HTML equivalent of the plain text data b.
|
|
||||||
func HTMLEscape(w io.Writer, b []byte) {
|
|
||||||
last := 0
|
|
||||||
for i, c := range b {
|
|
||||||
var html []byte
|
|
||||||
switch c {
|
|
||||||
case '"':
|
|
||||||
html = htmlQuot
|
|
||||||
case '\'':
|
|
||||||
html = htmlApos
|
|
||||||
case '&':
|
|
||||||
html = htmlAmp
|
|
||||||
case '<':
|
|
||||||
html = htmlLt
|
|
||||||
case '>':
|
|
||||||
html = htmlGt
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
w.Write(b[last:i])
|
|
||||||
w.Write(html)
|
|
||||||
last = i + 1
|
|
||||||
}
|
|
||||||
w.Write(b[last:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
|
|
||||||
func HTMLEscapeString(s string) string {
|
|
||||||
// Avoid allocation if we can.
|
|
||||||
if strings.IndexAny(s, `'"&<>`) < 0 {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
var b bytes.Buffer
|
|
||||||
HTMLEscape(&b, []byte(s))
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTMLEscaper returns the escaped HTML equivalent of the textual
|
|
||||||
// representation of its arguments.
|
|
||||||
func HTMLEscaper(args ...interface{}) string {
|
|
||||||
return HTMLEscapeString(evalArgs(args))
|
|
||||||
}
|
|
||||||
|
|
||||||
// JavaScript escaping.
|
|
||||||
|
|
||||||
var (
|
|
||||||
jsLowUni = []byte(`\u00`)
|
|
||||||
hex = []byte("0123456789ABCDEF")
|
|
||||||
|
|
||||||
jsBackslash = []byte(`\\`)
|
|
||||||
jsApos = []byte(`\'`)
|
|
||||||
jsQuot = []byte(`\"`)
|
|
||||||
jsLt = []byte(`\x3C`)
|
|
||||||
jsGt = []byte(`\x3E`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// JSEscape writes to w the escaped JavaScript equivalent of the plain text data b.
|
|
||||||
func JSEscape(w io.Writer, b []byte) {
|
|
||||||
last := 0
|
|
||||||
for i := 0; i < len(b); i++ {
|
|
||||||
c := b[i]
|
|
||||||
|
|
||||||
if !jsIsSpecial(rune(c)) {
|
|
||||||
// fast path: nothing to do
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
w.Write(b[last:i])
|
|
||||||
|
|
||||||
if c < utf8.RuneSelf {
|
|
||||||
// Quotes, slashes and angle brackets get quoted.
|
|
||||||
// Control characters get written as \u00XX.
|
|
||||||
switch c {
|
|
||||||
case '\\':
|
|
||||||
w.Write(jsBackslash)
|
|
||||||
case '\'':
|
|
||||||
w.Write(jsApos)
|
|
||||||
case '"':
|
|
||||||
w.Write(jsQuot)
|
|
||||||
case '<':
|
|
||||||
w.Write(jsLt)
|
|
||||||
case '>':
|
|
||||||
w.Write(jsGt)
|
|
||||||
default:
|
|
||||||
w.Write(jsLowUni)
|
|
||||||
t, b := c>>4, c&0x0f
|
|
||||||
w.Write(hex[t : t+1])
|
|
||||||
w.Write(hex[b : b+1])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Unicode rune.
|
|
||||||
r, size := utf8.DecodeRune(b[i:])
|
|
||||||
if unicode.IsPrint(r) {
|
|
||||||
w.Write(b[i : i+size])
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(w, "\\u%04X", r)
|
|
||||||
}
|
|
||||||
i += size - 1
|
|
||||||
}
|
|
||||||
last = i + 1
|
|
||||||
}
|
|
||||||
w.Write(b[last:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSEscapeString returns the escaped JavaScript equivalent of the plain text data s.
|
|
||||||
func JSEscapeString(s string) string {
|
|
||||||
// Avoid allocation if we can.
|
|
||||||
if strings.IndexFunc(s, jsIsSpecial) < 0 {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
var b bytes.Buffer
|
|
||||||
JSEscape(&b, []byte(s))
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func jsIsSpecial(r rune) bool {
|
|
||||||
switch r {
|
|
||||||
case '\\', '\'', '"', '<', '>':
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return r < ' ' || utf8.RuneSelf <= r
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSEscaper returns the escaped JavaScript equivalent of the textual
|
|
||||||
// representation of its arguments.
|
|
||||||
func JSEscaper(args ...interface{}) string {
|
|
||||||
return JSEscapeString(evalArgs(args))
|
|
||||||
}
|
|
||||||
|
|
||||||
// URLQueryEscaper returns the escaped value of the textual representation of
|
|
||||||
// its arguments in a form suitable for embedding in a URL query.
|
|
||||||
func URLQueryEscaper(args ...interface{}) string {
|
|
||||||
return url.QueryEscape(evalArgs(args))
|
|
||||||
}
|
|
||||||
|
|
||||||
// evalArgs formats the list of arguments into a string. It is therefore equivalent to
|
|
||||||
// fmt.Sprint(args...)
|
|
||||||
// except that each argument is indirected (if a pointer), as required,
|
|
||||||
// using the same rules as the default string evaluation during template
|
|
||||||
// execution.
|
|
||||||
func evalArgs(args []interface{}) string {
|
|
||||||
ok := false
|
|
||||||
var s string
|
|
||||||
// Fast path for simple common case.
|
|
||||||
if len(args) == 1 {
|
|
||||||
s, ok = args[0].(string)
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
for i, arg := range args {
|
|
||||||
a, ok := printableValue(reflect.ValueOf(arg))
|
|
||||||
if ok {
|
|
||||||
args[i] = a
|
|
||||||
} // else left fmt do its thing
|
|
||||||
}
|
|
||||||
s = fmt.Sprint(args...)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user