diff --git a/.idea/Go-Tool.iml b/.idea/Go-Tool.iml
index 0fb91b3..2bcd8a2 100644
--- a/.idea/Go-Tool.iml
+++ b/.idea/Go-Tool.iml
@@ -3,6 +3,7 @@
+
diff --git a/test/jdkContainer/SourceAnalysis/heap.go b/SourceAnalysisAndTool/jdkContainer/sourceAnalysis/heap.go
similarity index 99%
rename from test/jdkContainer/SourceAnalysis/heap.go
rename to SourceAnalysisAndTool/jdkContainer/sourceAnalysis/heap.go
index 73a4b83..5783359 100644
--- a/test/jdkContainer/SourceAnalysis/heap.go
+++ b/SourceAnalysisAndTool/jdkContainer/sourceAnalysis/heap.go
@@ -15,7 +15,7 @@
// implementation; the file example_pq_test.go has the complete source.
//
//read note 拷贝一个代码过来解析.感觉在go里面拷贝代码简单多了,依赖可以直接使用。我在这边使用read note(自定义todo标识)来标识我的解析.
-package SourceAnalysis
+package sourceAnalysis
import "sort"
diff --git a/test/jdkContainer/SourceAnalysis/list.go b/SourceAnalysisAndTool/jdkContainer/sourceAnalysis/list.go
similarity index 99%
rename from test/jdkContainer/SourceAnalysis/list.go
rename to SourceAnalysisAndTool/jdkContainer/sourceAnalysis/list.go
index 0afdff1..8b65bf8 100644
--- a/test/jdkContainer/SourceAnalysis/list.go
+++ b/SourceAnalysisAndTool/jdkContainer/sourceAnalysis/list.go
@@ -9,7 +9,7 @@
// // do something with e.Value
// }
//
-package SourceAnalysis
+package sourceAnalysis
// Element is an element of a linked list.
//read note list中对应的元素,list相当是通过一个链表来链接所有的Element元素.
diff --git a/test/jdkContainer/SourceAnalysis/ring.go b/SourceAnalysisAndTool/jdkContainer/sourceAnalysis/ring.go
similarity index 99%
rename from test/jdkContainer/SourceAnalysis/ring.go
rename to SourceAnalysisAndTool/jdkContainer/sourceAnalysis/ring.go
index 80b1036..063a361 100644
--- a/test/jdkContainer/SourceAnalysis/ring.go
+++ b/SourceAnalysisAndTool/jdkContainer/sourceAnalysis/ring.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// Package ring implements operations on circular lists.
-package SourceAnalysis
+package sourceAnalysis
// A Ring is an element of a circular list, or ring.
// Rings do not have a beginning or end; a pointer to any ring element
diff --git a/test/jdkContainer/testHeap/HeapTool.go b/SourceAnalysisAndTool/jdkContainer/testHeap/HeapTool.go
similarity index 100%
rename from test/jdkContainer/testHeap/HeapTool.go
rename to SourceAnalysisAndTool/jdkContainer/testHeap/HeapTool.go
diff --git a/test/jdkContainer/testHeap/heap_test.go b/SourceAnalysisAndTool/jdkContainer/testHeap/heap_test.go
similarity index 100%
rename from test/jdkContainer/testHeap/heap_test.go
rename to SourceAnalysisAndTool/jdkContainer/testHeap/heap_test.go
diff --git a/test/jdkContainer/testHeap/list_test.go b/SourceAnalysisAndTool/jdkContainer/testHeap/list_test.go
similarity index 100%
rename from test/jdkContainer/testHeap/list_test.go
rename to SourceAnalysisAndTool/jdkContainer/testHeap/list_test.go
diff --git a/test/jdkContainer/testHeap/ring_test.go b/SourceAnalysisAndTool/jdkContainer/testHeap/ring_test.go
similarity index 100%
rename from test/jdkContainer/testHeap/ring_test.go
rename to SourceAnalysisAndTool/jdkContainer/testHeap/ring_test.go
diff --git a/SourceAnalysisAndTool/validator.v8/2、结构体缓存获取.jpg b/SourceAnalysisAndTool/validator.v8/2、结构体缓存获取.jpg
new file mode 100644
index 0000000..8eadd1a
Binary files /dev/null and b/SourceAnalysisAndTool/validator.v8/2、结构体缓存获取.jpg differ
diff --git a/SourceAnalysisAndTool/validator.v8/readme.md b/SourceAnalysisAndTool/validator.v8/readme.md
new file mode 100644
index 0000000..29bb391
--- /dev/null
+++ b/SourceAnalysisAndTool/validator.v8/readme.md
@@ -0,0 +1,5 @@
+我的分析文章可参考:[Go源码解析:validator.v8](https://blog.csdn.net/qq_34326321/article/details/111030128)
+
+流程图: 
+
+流程图地址:[地址](https://www.processon.com/view/link/5fd6dabb63768906e6db0d25)
\ No newline at end of file
diff --git a/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/.gitignore b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/.gitignore
new file mode 100644
index 0000000..792ca00
--- /dev/null
+++ b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/.gitignore
@@ -0,0 +1,29 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
+*.test
+*.out
+*.txt
+cover.html
+README.html
\ No newline at end of file
diff --git a/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/LICENSE b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/LICENSE
new file mode 100644
index 0000000..6a2ae9a
--- /dev/null
+++ b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Dean Karn
+
+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.
+
diff --git a/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/README.md b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/README.md
new file mode 100644
index 0000000..d3bd9b0
--- /dev/null
+++ b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/README.md
@@ -0,0 +1,366 @@
+Package validator
+================
+
[](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+[](https://semaphoreci.com/joeybloggs/validator)
+[](https://coveralls.io/github/go-playground/validator?branch=v8)
+[](https://goreportcard.com/report/github.com/go-playground/validator)
+[](https://godoc.org/gopkg.in/go-playground/validator.v8)
+
+
+Package validator implements value validations for structs and individual fields based on tags.
+
+It has the following **unique** features:
+
+- Cross Field and Cross Struct validations by using validation tags or custom validators.
+- Slice, Array and Map diving, which allows any or all levels of a multidimensional field to be validated.
+- Handles type interface by determining it's underlying type prior to validation.
+- Handles custom field types such as sql driver Valuer see [Valuer](https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29)
+- Alias validation tags, which allows for mapping of several validations to a single tag for easier defining of validations on structs
+- Extraction of custom defined Field Name e.g. can specify to extract the JSON name while validating and have it available in the resulting FieldError
+
+Installation
+------------
+
+Use go get.
+
+ go get gopkg.in/go-playground/validator.v8
+
+or to update
+
+ go get -u gopkg.in/go-playground/validator.v8
+
+Then import the validator package into your own code.
+
+ import "gopkg.in/go-playground/validator.v8"
+
+Error Return Value
+-------
+
+Validation functions return type error
+
+They return type error to avoid the issue discussed in the following, where err is always != nil:
+
+* http://stackoverflow.com/a/29138676/3158232
+* https://github.com/go-playground/validator/issues/134
+
+validator only returns nil or ValidationErrors as type error; so in you code all you need to do
+is check if the error returned is not nil, and if it's not type cast it to type ValidationErrors
+like so:
+
+```go
+err := validate.Struct(mystruct)
+validationErrors := err.(validator.ValidationErrors)
+ ```
+
+Usage and documentation
+------
+
+Please see http://godoc.org/gopkg.in/go-playground/validator.v8 for detailed usage docs.
+
+##### Examples:
+
+Struct & Field validation
+```go
+package main
+
+import (
+ "fmt"
+
+ "gopkg.in/go-playground/validator.v8"
+)
+
+// User contains user information
+type User struct {
+ FirstName string `validate:"required"`
+ LastName string `validate:"required"`
+ Age uint8 `validate:"gte=0,lte=130"`
+ Email string `validate:"required,email"`
+ FavouriteColor string `validate:"hexcolor|rgb|rgba"`
+ Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
+}
+
+// Address houses a users address information
+type Address struct {
+ Street string `validate:"required"`
+ City string `validate:"required"`
+ Planet string `validate:"required"`
+ Phone string `validate:"required"`
+}
+
+var validate *validator.Validate
+
+func main() {
+
+ config := &validator.Config{TagName: "validate"}
+
+ validate = validator.New(config)
+
+ validateStruct()
+ validateField()
+}
+
+func validateStruct() {
+
+ address := &Address{
+ Street: "Eavesdown Docks",
+ Planet: "Persphone",
+ Phone: "none",
+ }
+
+ user := &User{
+ FirstName: "Badger",
+ LastName: "Smith",
+ Age: 135,
+ Email: "Badger.Smith@gmail.com",
+ FavouriteColor: "#000",
+ Addresses: []*Address{address},
+ }
+
+ // returns nil or ValidationErrors ( map[string]*FieldError )
+ errs := validate.Struct(user)
+
+ if errs != nil {
+
+ fmt.Println(errs) // output: Key: "User.Age" Error:Field validation for "Age" failed on the "lte" tag
+ // Key: "User.Addresses[0].City" Error:Field validation for "City" failed on the "required" tag
+ err := errs.(validator.ValidationErrors)["User.Addresses[0].City"]
+ fmt.Println(err.Field) // output: City
+ fmt.Println(err.Tag) // output: required
+ fmt.Println(err.Kind) // output: string
+ fmt.Println(err.Type) // output: string
+ fmt.Println(err.Param) // output:
+ fmt.Println(err.Value) // output:
+
+ // from here you can create your own error messages in whatever language you wish
+ return
+ }
+
+ // save user to database
+}
+
+func validateField() {
+ myEmail := "joeybloggs.gmail.com"
+
+ errs := validate.Field(myEmail, "required,email")
+
+ if errs != nil {
+ fmt.Println(errs) // output: Key: "" Error:Field validation for "" failed on the "email" tag
+ return
+ }
+
+ // email ok, move on
+}
+```
+
+Custom Field Type
+```go
+package main
+
+import (
+ "database/sql"
+ "database/sql/driver"
+ "fmt"
+ "reflect"
+
+ "gopkg.in/go-playground/validator.v8"
+)
+
+// DbBackedUser User struct
+type DbBackedUser struct {
+ Name sql.NullString `validate:"required"`
+ Age sql.NullInt64 `validate:"required"`
+}
+
+func main() {
+
+ config := &validator.Config{TagName: "validate"}
+
+ validate := validator.New(config)
+
+ // register all sql.Null* types to use the ValidateValuer CustomTypeFunc
+ validate.RegisterCustomTypeFunc(ValidateValuer, sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{})
+
+ x := DbBackedUser{Name: sql.NullString{String: "", Valid: true}, Age: sql.NullInt64{Int64: 0, Valid: false}}
+ errs := validate.Struct(x)
+
+ if len(errs.(validator.ValidationErrors)) > 0 {
+ fmt.Printf("Errs:\n%+v\n", errs)
+ }
+}
+
+// ValidateValuer implements validator.CustomTypeFunc
+func ValidateValuer(field reflect.Value) interface{} {
+ if valuer, ok := field.Interface().(driver.Valuer); ok {
+ val, err := valuer.Value()
+ if err == nil {
+ return val
+ }
+ // handle the error how you want
+ }
+ return nil
+}
+```
+
+Struct Level Validation
+```go
+package main
+
+import (
+ "fmt"
+ "reflect"
+
+ "gopkg.in/go-playground/validator.v8"
+)
+
+// User contains user information
+type User struct {
+ FirstName string `json:"fname"`
+ LastName string `json:"lname"`
+ Age uint8 `validate:"gte=0,lte=130"`
+ Email string `validate:"required,email"`
+ FavouriteColor string `validate:"hexcolor|rgb|rgba"`
+ Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
+}
+
+// Address houses a users address information
+type Address struct {
+ Street string `validate:"required"`
+ City string `validate:"required"`
+ Planet string `validate:"required"`
+ Phone string `validate:"required"`
+}
+
+var validate *validator.Validate
+
+func main() {
+
+ config := &validator.Config{TagName: "validate"}
+
+ validate = validator.New(config)
+ validate.RegisterStructValidation(UserStructLevelValidation, User{})
+
+ validateStruct()
+}
+
+// UserStructLevelValidation contains custom struct level validations that don't always
+// make sense at the field validation level. For Example this function validates that either
+// FirstName or LastName exist; could have done that with a custom field validation but then
+// would have had to add it to both fields duplicating the logic + overhead, this way it's
+// only validated once.
+//
+// NOTE: you may ask why wouldn't I just do this outside of validator, because doing this way
+// hooks right into validator and you can combine with validation tags and still have a
+// common error output format.
+func UserStructLevelValidation(v *validator.Validate, structLevel *validator.StructLevel) {
+
+ user := structLevel.CurrentStruct.Interface().(User)
+
+ if len(user.FirstName) == 0 && len(user.LastName) == 0 {
+ structLevel.ReportError(reflect.ValueOf(user.FirstName), "FirstName", "fname", "fnameorlname")
+ structLevel.ReportError(reflect.ValueOf(user.LastName), "LastName", "lname", "fnameorlname")
+ }
+
+ // plus can to more, even with different tag than "fnameorlname"
+}
+
+func validateStruct() {
+
+ address := &Address{
+ Street: "Eavesdown Docks",
+ Planet: "Persphone",
+ Phone: "none",
+ City: "Unknown",
+ }
+
+ user := &User{
+ FirstName: "",
+ LastName: "",
+ Age: 45,
+ Email: "Badger.Smith@gmail.com",
+ FavouriteColor: "#000",
+ Addresses: []*Address{address},
+ }
+
+ // returns nil or ValidationErrors ( map[string]*FieldError )
+ errs := validate.Struct(user)
+
+ if errs != nil {
+
+ fmt.Println(errs) // output: Key: 'User.LastName' Error:Field validation for 'LastName' failed on the 'fnameorlname' tag
+ // Key: 'User.FirstName' Error:Field validation for 'FirstName' failed on the 'fnameorlname' tag
+ err := errs.(validator.ValidationErrors)["User.FirstName"]
+ fmt.Println(err.Field) // output: FirstName
+ fmt.Println(err.Tag) // output: fnameorlname
+ fmt.Println(err.Kind) // output: string
+ fmt.Println(err.Type) // output: string
+ fmt.Println(err.Param) // output:
+ fmt.Println(err.Value) // output:
+
+ // from here you can create your own error messages in whatever language you wish
+ return
+ }
+
+ // save user to database
+}
+```
+
+Benchmarks
+------
+###### Run on MacBook Pro (Retina, 15-inch, Late 2013) 2.6 GHz Intel Core i7 16 GB 1600 MHz DDR3 using Go version go1.5.3 darwin/amd64
+```go
+PASS
+BenchmarkFieldSuccess-8 20000000 118 ns/op 0 B/op 0 allocs/op
+BenchmarkFieldFailure-8 2000000 758 ns/op 432 B/op 4 allocs/op
+BenchmarkFieldDiveSuccess-8 500000 2471 ns/op 464 B/op 28 allocs/op
+BenchmarkFieldDiveFailure-8 500000 3172 ns/op 896 B/op 32 allocs/op
+BenchmarkFieldCustomTypeSuccess-8 5000000 300 ns/op 32 B/op 2 allocs/op
+BenchmarkFieldCustomTypeFailure-8 2000000 775 ns/op 432 B/op 4 allocs/op
+BenchmarkFieldOrTagSuccess-8 1000000 1122 ns/op 4 B/op 1 allocs/op
+BenchmarkFieldOrTagFailure-8 1000000 1167 ns/op 448 B/op 6 allocs/op
+BenchmarkStructLevelValidationSuccess-8 3000000 548 ns/op 160 B/op 5 allocs/op
+BenchmarkStructLevelValidationFailure-8 3000000 558 ns/op 160 B/op 5 allocs/op
+BenchmarkStructSimpleCustomTypeSuccess-8 2000000 623 ns/op 36 B/op 3 allocs/op
+BenchmarkStructSimpleCustomTypeFailure-8 1000000 1381 ns/op 640 B/op 9 allocs/op
+BenchmarkStructPartialSuccess-8 1000000 1036 ns/op 272 B/op 9 allocs/op
+BenchmarkStructPartialFailure-8 1000000 1734 ns/op 730 B/op 14 allocs/op
+BenchmarkStructExceptSuccess-8 2000000 888 ns/op 250 B/op 7 allocs/op
+BenchmarkStructExceptFailure-8 1000000 1036 ns/op 272 B/op 9 allocs/op
+BenchmarkStructSimpleCrossFieldSuccess-8 2000000 773 ns/op 80 B/op 4 allocs/op
+BenchmarkStructSimpleCrossFieldFailure-8 1000000 1487 ns/op 536 B/op 9 allocs/op
+BenchmarkStructSimpleCrossStructCrossFieldSuccess-8 1000000 1261 ns/op 112 B/op 7 allocs/op
+BenchmarkStructSimpleCrossStructCrossFieldFailure-8 1000000 2055 ns/op 576 B/op 12 allocs/op
+BenchmarkStructSimpleSuccess-8 3000000 519 ns/op 4 B/op 1 allocs/op
+BenchmarkStructSimpleFailure-8 1000000 1429 ns/op 640 B/op 9 allocs/op
+BenchmarkStructSimpleSuccessParallel-8 10000000 146 ns/op 4 B/op 1 allocs/op
+BenchmarkStructSimpleFailureParallel-8 2000000 551 ns/op 640 B/op 9 allocs/op
+BenchmarkStructComplexSuccess-8 500000 3269 ns/op 244 B/op 15 allocs/op
+BenchmarkStructComplexFailure-8 200000 8436 ns/op 3609 B/op 60 allocs/op
+BenchmarkStructComplexSuccessParallel-8 1000000 1024 ns/op 244 B/op 15 allocs/op
+BenchmarkStructComplexFailureParallel-8 500000 3536 ns/op 3609 B/op 60 allocs/op
+```
+
+Complimentary Software
+----------------------
+
+Here is a list of software that compliments using this library either pre or post validation.
+
+* [form](https://github.com/go-playground/form) - Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. Dual Array and Full map support.
+* [Conform](https://github.com/leebenson/conform) - Trims, sanitizes & scrubs data based on struct tags.
+
+How to Contribute
+------
+
+There will always be a development branch for each version i.e. `v1-development`. In order to contribute,
+please make your pull requests against those branches.
+
+If the changes being proposed or requested are breaking changes, please create an issue, for discussion
+or create a pull request against the highest development branch for example this package has a
+v1 and v1-development branch however, there will also be a v2-development branch even though v2 doesn't exist yet.
+
+I strongly encourage everyone whom creates a custom validation function to contribute them and
+help make this package even better.
+
+License
+------
+Distributed under MIT License, please see license file in code for more details.
diff --git a/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/baked_in.go b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/baked_in.go
new file mode 100644
index 0000000..558616e
--- /dev/null
+++ b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/baked_in.go
@@ -0,0 +1,1429 @@
+package validator
+
+import (
+ "fmt"
+ "net"
+ "net/url"
+ "reflect"
+ "strings"
+ "time"
+ "unicode/utf8"
+)
+
+// BakedInAliasValidators is a default mapping of a single validationstag that
+// defines a common or complex set of validation(s) to simplify
+// adding validation to structs. i.e. set key "_ageok" and the tags
+// are "gt=0,lte=130" or key "_preferredname" and tags "omitempty,gt=0,lte=60"
+//read note 别名标签,通过别名定义规则,默认是iscolor
+// 它的作用比较神奇,就是说通过iscolor这个标签就可以判断后面一组的规则
+// 比如说这边 iscolor对应的是 hexcolor|rgb|rgba|hsl|hsla
+// 如果我在tag中使用iscolor标签,则validator会去校验 是否满足 hexcolor | 是否满足 rgb | 是否满足 rgba | 是否满足 hsl | 是否满足 hsla (|:或者)
+var bakedInAliasValidators = map[string]string{
+ "iscolor": "hexcolor|rgb|rgba|hsl|hsla",
+}
+
+// BakedInValidators is the default map of ValidationFunc
+// you can add, remove or even replace items to suite your needs,
+// or even disregard and use your own map if so desired.
+//read note 默认的校验映射map. key是tag标签,value是对应tag标签的处理类
+// 具体校验实现可参考:https://blog.csdn.net/weixin_30896511/article/details/98428064
+var bakedInValidators = map[string]Func{
+ "required": HasValue, //read note 参数需要有值
+ "len": HasLengthOf, //read note 数值类型判断的是值相等, Map Slice Array判断的是长度相等,string判断的是Rune数组长度相等
+ "min": HasMinOf, //read note 数值类型判断的是值【大于等于】min, Map Slice Array判断的是长度【大于等于】min,string判断的是Rune数组长度【大于等于】min
+ "max": HasMaxOf, //read note 数值类型判断的是值【小于等于】max, Map Slice Array判断的是长度【小于等于】max,string判断的是Rune数组长度【小于等于】max
+ "eq": IsEq, //read note 字符串或者数值类型,判断的是值【相等】,Map Slice Array判断长度是否【相等】
+ "ne": IsNe, //read note 字符串或者数值类型,判断的是值【不相等】,Map Slice Array判断长度是否【不相等】
+ "lt": IsLt, //read note 数值类型判断的是值【小于】lt, Map Slice Array判断的是长度【小于】lt,string判断的是Rune数组长度【小于】lt
+ "lte": IsLte, //类似max的操作,但是这边多了一步处理就是判断如果是【time.Time】,比较时间在当前时间之前或者等于当前时间
+ "gt": IsGt, //read note 数值类型判断的是值【大于】gt, Map Slice Array判断的是长度【大于】gt,string判断的是Rune数组长度【大于】gt
+ "gte": IsGte, //类似min的操作,但是这边多了一步处理就是判断如果是【time.Time】,比较时间在当前时间之后或者等于当前时间
+
+ //read note 判断关联字段(标签标识关联字段的名字)和当前字段的值的关系,数值是判断值相等,Map Slice Array判断长度,如果有time.Time判断时间和当前时间前后关系,否则判断reflect.String
+ "eqfield": IsEqField,
+ "eqcsfield": IsEqCrossStructField,
+ "necsfield": IsNeCrossStructField,
+ "gtcsfield": IsGtCrossStructField,
+ "gtecsfield": IsGteCrossStructField,
+ "ltcsfield": IsLtCrossStructField,
+ "ltecsfield": IsLteCrossStructField,
+ "nefield": IsNeField,
+ "gtefield": IsGteField,
+ "gtfield": IsGtField,
+ "ltefield": IsLteField,
+ "ltfield": IsLtField,
+
+ "alpha": IsAlpha, //这将验证字符串值是否仅包含ASCII字母字符
+ "alphanum": IsAlphanum, //这将验证字符串值是否仅包含ASCII字母数字字符
+
+ "numeric": IsNumeric, //这将验证字符串值是否包含基本数值。基本排除指数等...对于整数或浮点数,它返回true。
+ "number": IsNumber, //判断是否Number
+ "hexadecimal": IsHexadecimal, //这将验证字符串值是否包含有效的十六进制
+
+ "hexcolor": IsHEXColor, //这验证字符串值包含有效的十六进制颜色,包括#标签(#)
+ "rgb": IsRGB, //这将验证字符串值是否包含有效的rgb颜色
+ "rgba": IsRGBA, //这将验证字符串值是否包含有效的rgba颜色
+ "hsl": IsHSL, //这将验证字符串值是否包含有效的hsl颜色
+ "hsla": IsHSLA, //这将验证字符串值是否包含有效的hsla颜色
+
+ "email": IsEmail, //这验证字符串值包含有效的电子邮件这可能不符合任何rfc标准的所有可能性,但任何电子邮件提供商都不接受所有可能性
+ "url": IsURL, //这会验证字符串值是否包含有效的url这将接受golang请求uri接受的任何url,但必须包含一个模式,例如http://或rtmp://
+ "uri": IsURI, //这验证了字符串值包含有效的uri。这将接受uri接受的golang请求的任何uri
+ "base64": IsBase64, //这将验证字符串值是否包含有效的base64值。虽然空字符串是有效的base64,但这会将空字符串报告为错误,如果您希望接受空字符串作为有效字符,则可以将此字符串与omitempty标记一起使用。
+
+ //read note 验证字符串是否【包含】/【不包含】对应的子字符串(这个方法看源码是处理Field.String()是否包含对应的子串,而如果不是字符串的话返回的是,不知道这个会不会被对比)
+ "contains": Contains,
+ "containsany": ContainsAny,
+ "containsrune": ContainsRune,
+ "excludes": Excludes,
+ "excludesall": ExcludesAll,
+ "excludesrune": ExcludesRune,
+
+ //read note 校验字符串是否有效的isbn值
+ "isbn": IsISBN,
+ "isbn10": IsISBN10,
+ "isbn13": IsISBN13,
+
+ //read note 校验字符串是否有效的uuid值
+ "uuid": IsUUID,
+ "uuid3": IsUUID3,
+ "uuid4": IsUUID4,
+ "uuid5": IsUUID5,
+
+ "ascii": IsASCII, //这将验证字符串值是否仅包含ASCII字符。注意:如果字符串为空,则验证为true
+ "printascii": IsPrintableASCII, //这将验证字符串值是否仅包含可打印的ASCII字符。注意:如果字符串为空,则验证为true。
+ "multibyte": HasMultiByteCharacter, //这将验证字符串值是否包含一个或多个多字节字符。注意:如果字符串为空,则验证为true
+ "datauri": IsDataURI, //这将验证字符串值是否包含有效的DataURI。注意:这也将验证数据部分是否有效base64
+ "latitude": IsLatitude, //这将验证字符串值是否包含有效的纬度。
+ "longitude": IsLongitude, //这将验证字符串值是否包含有效经度。
+ "ssn": IsSSN, //这将验证字符串值是否包含有效的美国社会安全号码。
+ "ipv4": IsIPv4, //这将验证字符串值是否包含有效的v4 IP地址
+ "ipv6": IsIPv6, //这将验证字符串值是否包含有效的v6 IP地址
+ "ip": IsIP, //这将验证字符串值是否包含有效的IP地址
+ "cidrv4": IsCIDRv4, //这将验证字符串值是否包含有效的v4 CIDR地址
+ "cidrv6": IsCIDRv6, //这将验证字符串值是否包含有效的v6 CIDR地址
+ "cidr": IsCIDR, //这将验证字符串值是否包含有效的CIDR地址
+ "tcp4_addr": IsTCP4AddrResolvable, //这将验证字符串值是否包含有效的可解析v4 TCP地址
+ "tcp6_addr": IsTCP6AddrResolvable, //这将验证字符串值是否包含有效的可解析v6 TCP地址
+ "tcp_addr": IsTCPAddrResolvable, //这将验证字符串值是否包含有效的可解析TCP地址
+ "udp4_addr": IsUDP4AddrResolvable, //这将验证字符串值是否包含有效的可解析v4 UDP地址
+ "udp6_addr": IsUDP6AddrResolvable, //这将验证字符串值是否包含有效的可解析v6 UDP地址
+ "udp_addr": IsUDPAddrResolvable, //这将验证字符串值是否包含有效的可解析UDP地址
+ "ip4_addr": IsIP4AddrResolvable, //这将验证字符串值是否包含有效的可解析v4 IP地址
+ "ip6_addr": IsIP6AddrResolvable, //这将验证字符串值是否包含有效的可解析v6 IP地址
+ "ip_addr": IsIPAddrResolvable, //这将验证字符串值是否包含有效的可解析IP地址
+ "unix_addr": IsUnixAddrResolvable, //这将验证字符串值是否包含有效的Unix地址
+ "mac": IsMAC, //这将验证字符串值是否包含有效的MAC地址
+}
+
+// IsMAC is the validation function for validating if the field's value is a valid MAC address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsMAC(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ _, err := net.ParseMAC(field.String())
+ return err == nil
+}
+
+// IsCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsCIDRv4(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ ip, _, err := net.ParseCIDR(field.String())
+
+ return err == nil && ip.To4() != nil
+}
+
+// IsCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsCIDRv6(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ ip, _, err := net.ParseCIDR(field.String())
+
+ return err == nil && ip.To4() == nil
+}
+
+// IsCIDR is the validation function for validating if the field's value is a valid v4 or v6 CIDR address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsCIDR(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ _, _, err := net.ParseCIDR(field.String())
+
+ return err == nil
+}
+
+// IsIPv4 is the validation function for validating if a value is a valid v4 IP address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsIPv4(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ ip := net.ParseIP(field.String())
+
+ return ip != nil && ip.To4() != nil
+}
+
+// IsIPv6 is the validation function for validating if the field's value is a valid v6 IP address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsIPv6(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ ip := net.ParseIP(field.String())
+
+ return ip != nil && ip.To4() == nil
+}
+
+// IsIP is the validation function for validating if the field's value is a valid v4 or v6 IP address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsIP(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ ip := net.ParseIP(field.String())
+
+ return ip != nil
+}
+
+// IsSSN is the validation function for validating if the field's value is a valid SSN.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsSSN(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ if field.Len() != 11 {
+ return false
+ }
+
+ return sSNRegex.MatchString(field.String())
+}
+
+// IsLongitude is the validation function for validating if the field's value is a valid longitude coordinate.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsLongitude(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return longitudeRegex.MatchString(field.String())
+}
+
+// IsLatitude is the validation function for validating if the field's value is a valid latitude coordinate.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsLatitude(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return latitudeRegex.MatchString(field.String())
+}
+
+// IsDataURI is the validation function for validating if the field's value is a valid data URI.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsDataURI(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ uri := strings.SplitN(field.String(), ",", 2)
+
+ if len(uri) != 2 {
+ return false
+ }
+
+ if !dataURIRegex.MatchString(uri[0]) {
+ return false
+ }
+
+ fld := reflect.ValueOf(uri[1])
+
+ return IsBase64(v, topStruct, currentStructOrField, fld, fld.Type(), fld.Kind(), param)
+}
+
+// HasMultiByteCharacter is the validation function for validating if the field's value has a multi byte character.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func HasMultiByteCharacter(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ if field.Len() == 0 {
+ return true
+ }
+
+ return multibyteRegex.MatchString(field.String())
+}
+
+// IsPrintableASCII is the validation function for validating if the field's value is a valid printable ASCII character.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsPrintableASCII(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return printableASCIIRegex.MatchString(field.String())
+}
+
+// IsASCII is the validation function for validating if the field's value is a valid ASCII character.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsASCII(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return aSCIIRegex.MatchString(field.String())
+}
+
+// IsUUID5 is the validation function for validating if the field's value is a valid v5 UUID.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsUUID5(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return uUID5Regex.MatchString(field.String())
+}
+
+// IsUUID4 is the validation function for validating if the field's value is a valid v4 UUID.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsUUID4(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return uUID4Regex.MatchString(field.String())
+}
+
+// IsUUID3 is the validation function for validating if the field's value is a valid v3 UUID.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsUUID3(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return uUID3Regex.MatchString(field.String())
+}
+
+// IsUUID is the validation function for validating if the field's value is a valid UUID of any version.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsUUID(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return uUIDRegex.MatchString(field.String())
+}
+
+// IsISBN is the validation function for validating if the field's value is a valid v10 or v13 ISBN.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsISBN(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return IsISBN10(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) || IsISBN13(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param)
+}
+
+// IsISBN13 is the validation function for validating if the field's value is a valid v13 ISBN.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsISBN13(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ s := strings.Replace(strings.Replace(field.String(), "-", "", 4), " ", "", 4)
+
+ if !iSBN13Regex.MatchString(s) {
+ return false
+ }
+
+ var checksum int32
+ var i int32
+
+ factor := []int32{1, 3}
+
+ for i = 0; i < 12; i++ {
+ checksum += factor[i%2] * int32(s[i]-'0')
+ }
+
+ return (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0
+}
+
+// IsISBN10 is the validation function for validating if the field's value is a valid v10 ISBN.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsISBN10(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ s := strings.Replace(strings.Replace(field.String(), "-", "", 3), " ", "", 3)
+
+ if !iSBN10Regex.MatchString(s) {
+ return false
+ }
+
+ var checksum int32
+ var i int32
+
+ for i = 0; i < 9; i++ {
+ checksum += (i + 1) * int32(s[i]-'0')
+ }
+
+ if s[9] == 'X' {
+ checksum += 10 * 10
+ } else {
+ checksum += 10 * int32(s[9]-'0')
+ }
+
+ return checksum%11 == 0
+}
+
+// ExcludesRune is the validation function for validating that the field's value does not contain the rune specified within the param.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func ExcludesRune(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return !ContainsRune(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param)
+}
+
+// ExcludesAll is the validation function for validating that the field's value does not contain any of the characters specified within the param.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func ExcludesAll(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return !ContainsAny(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param)
+}
+
+// Excludes is the validation function for validating that the field's value does not contain the text specified within the param.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func Excludes(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return !Contains(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param)
+}
+
+// ContainsRune is the validation function for validating that the field's value contains the rune specified within the param.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func ContainsRune(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ r, _ := utf8.DecodeRuneInString(param)
+
+ return strings.ContainsRune(field.String(), r)
+}
+
+// ContainsAny is the validation function for validating that the field's value contains any of the characters specified within the param.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func ContainsAny(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return strings.ContainsAny(field.String(), param)
+}
+
+// Contains is the validation function for validating that the field's value contains the text specified within the param.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func Contains(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return strings.Contains(field.String(), param)
+}
+
+// IsNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsNeField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param)
+
+ if !ok || currentKind != fieldKind {
+ return true
+ }
+
+ switch fieldKind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return field.Int() != currentField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return field.Uint() != currentField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+ return field.Float() != currentField.Float()
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ return int64(field.Len()) != int64(currentField.Len())
+
+ case reflect.Struct:
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != currentField.Type() {
+ return true
+ }
+
+ if fieldType == timeType {
+
+ t := currentField.Interface().(time.Time)
+ fieldTime := field.Interface().(time.Time)
+
+ return !fieldTime.Equal(t)
+ }
+
+ }
+
+ // default reflect.String:
+ return field.String() != currentField.String()
+}
+
+// IsNe is the validation function for validating that the field's value does not equal the provided param value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsNe(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return !IsEq(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param)
+}
+
+// IsLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsLteCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ topField, topKind, ok := v.GetStructFieldOK(topStruct, param)
+ if !ok || topKind != fieldKind {
+ return false
+ }
+
+ switch fieldKind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return field.Int() <= topField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return field.Uint() <= topField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+ return field.Float() <= topField.Float()
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ return int64(field.Len()) <= int64(topField.Len())
+
+ case reflect.Struct:
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != topField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ fieldTime := field.Interface().(time.Time)
+ topTime := topField.Interface().(time.Time)
+
+ return fieldTime.Before(topTime) || fieldTime.Equal(topTime)
+ }
+ }
+
+ // default reflect.String:
+ return field.String() <= topField.String()
+}
+
+// IsLtCrossStructField is the validation function for validating if the current field's value is less than the field, within a separate struct, specified by the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsLtCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ topField, topKind, ok := v.GetStructFieldOK(topStruct, param)
+ if !ok || topKind != fieldKind {
+ return false
+ }
+
+ switch fieldKind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return field.Int() < topField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return field.Uint() < topField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+ return field.Float() < topField.Float()
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ return int64(field.Len()) < int64(topField.Len())
+
+ case reflect.Struct:
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != topField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ fieldTime := field.Interface().(time.Time)
+ topTime := topField.Interface().(time.Time)
+
+ return fieldTime.Before(topTime)
+ }
+ }
+
+ // default reflect.String:
+ return field.String() < topField.String()
+}
+
+// IsGteCrossStructField is the validation function for validating if the current field's value is greater than or equal to the field, within a separate struct, specified by the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsGteCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ topField, topKind, ok := v.GetStructFieldOK(topStruct, param)
+ if !ok || topKind != fieldKind {
+ return false
+ }
+
+ switch fieldKind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return field.Int() >= topField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return field.Uint() >= topField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+ return field.Float() >= topField.Float()
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ return int64(field.Len()) >= int64(topField.Len())
+
+ case reflect.Struct:
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != topField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ fieldTime := field.Interface().(time.Time)
+ topTime := topField.Interface().(time.Time)
+
+ return fieldTime.After(topTime) || fieldTime.Equal(topTime)
+ }
+ }
+
+ // default reflect.String:
+ return field.String() >= topField.String()
+}
+
+// IsGtCrossStructField is the validation function for validating if the current field's value is greater than the field, within a separate struct, specified by the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsGtCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ topField, topKind, ok := v.GetStructFieldOK(topStruct, param)
+ if !ok || topKind != fieldKind {
+ return false
+ }
+
+ switch fieldKind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return field.Int() > topField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return field.Uint() > topField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+ return field.Float() > topField.Float()
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ return int64(field.Len()) > int64(topField.Len())
+
+ case reflect.Struct:
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != topField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ fieldTime := field.Interface().(time.Time)
+ topTime := topField.Interface().(time.Time)
+
+ return fieldTime.After(topTime)
+ }
+ }
+
+ // default reflect.String:
+ return field.String() > topField.String()
+}
+
+// IsNeCrossStructField is the validation function for validating that the current field's value is not equal to the field, within a separate struct, specified by the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsNeCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ topField, currentKind, ok := v.GetStructFieldOK(topStruct, param)
+ if !ok || currentKind != fieldKind {
+ return true
+ }
+
+ switch fieldKind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return topField.Int() != field.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return topField.Uint() != field.Uint()
+
+ case reflect.Float32, reflect.Float64:
+ return topField.Float() != field.Float()
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ return int64(topField.Len()) != int64(field.Len())
+
+ case reflect.Struct:
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != topField.Type() {
+ return true
+ }
+
+ if fieldType == timeType {
+
+ t := field.Interface().(time.Time)
+ fieldTime := topField.Interface().(time.Time)
+
+ return !fieldTime.Equal(t)
+ }
+ }
+
+ // default reflect.String:
+ return topField.String() != field.String()
+}
+
+// IsEqCrossStructField is the validation function for validating that the current field's value is equal to the field, within a separate struct, specified by the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsEqCrossStructField(v *Validate, topStruct reflect.Value, current reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ topField, topKind, ok := v.GetStructFieldOK(topStruct, param)
+ if !ok || topKind != fieldKind {
+ return false
+ }
+
+ switch fieldKind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return topField.Int() == field.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return topField.Uint() == field.Uint()
+
+ case reflect.Float32, reflect.Float64:
+ return topField.Float() == field.Float()
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ return int64(topField.Len()) == int64(field.Len())
+
+ case reflect.Struct:
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != topField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ t := field.Interface().(time.Time)
+ fieldTime := topField.Interface().(time.Time)
+
+ return fieldTime.Equal(t)
+ }
+ }
+
+ // default reflect.String:
+ return topField.String() == field.String()
+}
+
+// IsEqField is the validation function for validating if the current field's value is equal to the field specified by the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsEqField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param)
+ if !ok || currentKind != fieldKind {
+ return false
+ }
+
+ switch fieldKind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return field.Int() == currentField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return field.Uint() == currentField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+ return field.Float() == currentField.Float()
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ return int64(field.Len()) == int64(currentField.Len())
+
+ case reflect.Struct:
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != currentField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ t := currentField.Interface().(time.Time)
+ fieldTime := field.Interface().(time.Time)
+
+ return fieldTime.Equal(t)
+ }
+
+ }
+
+ // default reflect.String:
+ return field.String() == currentField.String()
+}
+
+// IsEq is the validation function for validating if the current field's value is equal to the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsEq(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ switch fieldKind {
+
+ case reflect.String:
+ return field.String() == param
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ p := asInt(param)
+
+ return int64(field.Len()) == p
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p := asInt(param)
+
+ return field.Int() == p
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ p := asUint(param)
+
+ return field.Uint() == p
+
+ case reflect.Float32, reflect.Float64:
+ p := asFloat(param)
+
+ return field.Float() == p
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// IsBase64 is the validation function for validating if the current field's value is a valid base 64.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsBase64(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return base64Regex.MatchString(field.String())
+}
+
+// IsURI is the validation function for validating if the current field's value is a valid URI.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsURI(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ switch fieldKind {
+
+ case reflect.String:
+
+ s := field.String()
+
+ // checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195
+ // emulate browser and strip the '#' suffix prior to validation. see issue-#237
+ if i := strings.Index(s, "#"); i > -1 {
+ s = s[:i]
+ }
+
+ if s == blank {
+ return false
+ }
+
+ _, err := url.ParseRequestURI(s)
+
+ return err == nil
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// IsURL is the validation function for validating if the current field's value is a valid URL.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsURL(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ switch fieldKind {
+
+ case reflect.String:
+
+ var i int
+ s := field.String()
+
+ // checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195
+ // emulate browser and strip the '#' suffix prior to validation. see issue-#237
+ if i = strings.Index(s, "#"); i > -1 {
+ s = s[:i]
+ }
+
+ if s == blank {
+ return false
+ }
+
+ url, err := url.ParseRequestURI(s)
+
+ if err != nil || url.Scheme == blank {
+ return false
+ }
+
+ return err == nil
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// IsEmail is the validation function for validating if the current field's value is a valid email address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsEmail(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return emailRegex.MatchString(field.String())
+}
+
+// IsHSLA is the validation function for validating if the current field's value is a valid HSLA color.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsHSLA(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return hslaRegex.MatchString(field.String())
+}
+
+// IsHSL is the validation function for validating if the current field's value is a valid HSL color.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsHSL(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return hslRegex.MatchString(field.String())
+}
+
+// IsRGBA is the validation function for validating if the current field's value is a valid RGBA color.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsRGBA(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return rgbaRegex.MatchString(field.String())
+}
+
+// IsRGB is the validation function for validating if the current field's value is a valid RGB color.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsRGB(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return rgbRegex.MatchString(field.String())
+}
+
+// IsHEXColor is the validation function for validating if the current field's value is a valid HEX color.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsHEXColor(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return hexcolorRegex.MatchString(field.String())
+}
+
+// IsHexadecimal is the validation function for validating if the current field's value is a valid hexadecimal.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsHexadecimal(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return hexadecimalRegex.MatchString(field.String())
+}
+
+// IsNumber is the validation function for validating if the current field's value is a valid number.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsNumber(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return numberRegex.MatchString(field.String())
+}
+
+// IsNumeric is the validation function for validating if the current field's value is a valid numeric value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsNumeric(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return numericRegex.MatchString(field.String())
+}
+
+// IsAlphanum is the validation function for validating if the current field's value is a valid alphanumeric value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsAlphanum(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return alphaNumericRegex.MatchString(field.String())
+}
+
+// IsAlpha is the validation function for validating if the current field's value is a valid alpha value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsAlpha(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return alphaRegex.MatchString(field.String())
+}
+
+// HasValue is the validation function for validating if the current field's value is not the default static value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func HasValue(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ switch fieldKind {
+ case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
+ return !field.IsNil()
+ default:
+ return field.IsValid() && field.Interface() != reflect.Zero(fieldType).Interface()
+ }
+}
+
+// IsGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsGteField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param)
+ if !ok || currentKind != fieldKind {
+ return false
+ }
+
+ switch fieldKind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+
+ return field.Int() >= currentField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+
+ return field.Uint() >= currentField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+
+ return field.Float() >= currentField.Float()
+
+ case reflect.Struct:
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != currentField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ t := currentField.Interface().(time.Time)
+ fieldTime := field.Interface().(time.Time)
+
+ return fieldTime.After(t) || fieldTime.Equal(t)
+ }
+ }
+
+ // default reflect.String
+ return len(field.String()) >= len(currentField.String())
+}
+
+// IsGtField is the validation function for validating if the current field's value is greater than the field specified by the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsGtField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param)
+ if !ok || currentKind != fieldKind {
+ return false
+ }
+
+ switch fieldKind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+
+ return field.Int() > currentField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+
+ return field.Uint() > currentField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+
+ return field.Float() > currentField.Float()
+
+ case reflect.Struct:
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != currentField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ t := currentField.Interface().(time.Time)
+ fieldTime := field.Interface().(time.Time)
+
+ return fieldTime.After(t)
+ }
+ }
+
+ // default reflect.String
+ return len(field.String()) > len(currentField.String())
+}
+
+// IsGte is the validation function for validating if the current field's value is greater than or equal to the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsGte(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ switch fieldKind {
+
+ case reflect.String:
+ p := asInt(param)
+
+ return int64(utf8.RuneCountInString(field.String())) >= p
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ p := asInt(param)
+
+ return int64(field.Len()) >= p
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p := asInt(param)
+
+ return field.Int() >= p
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ p := asUint(param)
+
+ return field.Uint() >= p
+
+ case reflect.Float32, reflect.Float64:
+ p := asFloat(param)
+
+ return field.Float() >= p
+
+ case reflect.Struct:
+
+ if fieldType == timeType || fieldType == timePtrType {
+
+ now := time.Now().UTC()
+ t := field.Interface().(time.Time)
+
+ return t.After(now) || t.Equal(now)
+ }
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// IsGt is the validation function for validating if the current field's value is greater than the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsGt(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ switch fieldKind {
+
+ case reflect.String:
+ p := asInt(param)
+
+ return int64(utf8.RuneCountInString(field.String())) > p
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ p := asInt(param)
+
+ return int64(field.Len()) > p
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p := asInt(param)
+
+ return field.Int() > p
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ p := asUint(param)
+
+ return field.Uint() > p
+
+ case reflect.Float32, reflect.Float64:
+ p := asFloat(param)
+
+ return field.Float() > p
+ case reflect.Struct:
+
+ if fieldType == timeType || fieldType == timePtrType {
+
+ return field.Interface().(time.Time).After(time.Now().UTC())
+ }
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// HasLengthOf is the validation function for validating if the current field's value is equal to the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func HasLengthOf(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ switch fieldKind {
+
+ case reflect.String:
+ p := asInt(param)
+
+ return int64(utf8.RuneCountInString(field.String())) == p
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ p := asInt(param)
+
+ return int64(field.Len()) == p
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p := asInt(param)
+
+ return field.Int() == p
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ p := asUint(param)
+
+ return field.Uint() == p
+
+ case reflect.Float32, reflect.Float64:
+ p := asFloat(param)
+
+ return field.Float() == p
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// HasMinOf is the validation function for validating if the current field's value is greater than or equal to the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func HasMinOf(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ return IsGte(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param)
+}
+
+// IsLteField is the validation function for validating if the current field's value is less than or equal to the field specified by the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsLteField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param)
+ if !ok || currentKind != fieldKind {
+ return false
+ }
+
+ switch fieldKind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+
+ return field.Int() <= currentField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+
+ return field.Uint() <= currentField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+
+ return field.Float() <= currentField.Float()
+
+ case reflect.Struct:
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != currentField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ t := currentField.Interface().(time.Time)
+ fieldTime := field.Interface().(time.Time)
+
+ return fieldTime.Before(t) || fieldTime.Equal(t)
+ }
+ }
+
+ // default reflect.String
+ return len(field.String()) <= len(currentField.String())
+}
+
+// IsLtField is the validation function for validating if the current field's value is less than the field specified by the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsLtField(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ currentField, currentKind, ok := v.GetStructFieldOK(currentStructOrField, param)
+ if !ok || currentKind != fieldKind {
+ return false
+ }
+
+ switch fieldKind {
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+
+ return field.Int() < currentField.Int()
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+
+ return field.Uint() < currentField.Uint()
+
+ case reflect.Float32, reflect.Float64:
+
+ return field.Float() < currentField.Float()
+
+ case reflect.Struct:
+
+ // Not Same underlying type i.e. struct and time
+ if fieldType != currentField.Type() {
+ return false
+ }
+
+ if fieldType == timeType {
+
+ t := currentField.Interface().(time.Time)
+ fieldTime := field.Interface().(time.Time)
+
+ return fieldTime.Before(t)
+ }
+ }
+
+ // default reflect.String
+ return len(field.String()) < len(currentField.String())
+}
+
+// IsLte is the validation function for validating if the current field's value is less than or equal to the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsLte(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ switch fieldKind {
+
+ case reflect.String:
+ p := asInt(param)
+
+ return int64(utf8.RuneCountInString(field.String())) <= p
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ p := asInt(param)
+
+ return int64(field.Len()) <= p
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p := asInt(param)
+
+ return field.Int() <= p
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ p := asUint(param)
+
+ return field.Uint() <= p
+
+ case reflect.Float32, reflect.Float64:
+ p := asFloat(param)
+
+ return field.Float() <= p
+
+ case reflect.Struct:
+
+ if fieldType == timeType || fieldType == timePtrType {
+
+ now := time.Now().UTC()
+ t := field.Interface().(time.Time)
+
+ return t.Before(now) || t.Equal(now)
+ }
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// IsLt is the validation function for validating if the current field's value is less than the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsLt(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ switch fieldKind {
+
+ case reflect.String:
+ p := asInt(param)
+
+ return int64(utf8.RuneCountInString(field.String())) < p
+
+ case reflect.Slice, reflect.Map, reflect.Array:
+ p := asInt(param)
+
+ return int64(field.Len()) < p
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ p := asInt(param)
+
+ return field.Int() < p
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ p := asUint(param)
+
+ return field.Uint() < p
+
+ case reflect.Float32, reflect.Float64:
+ p := asFloat(param)
+
+ return field.Float() < p
+
+ case reflect.Struct:
+
+ if fieldType == timeType || fieldType == timePtrType {
+
+ return field.Interface().(time.Time).Before(time.Now().UTC())
+ }
+ }
+
+ panic(fmt.Sprintf("Bad field type %T", field.Interface()))
+}
+
+// HasMaxOf is the validation function for validating if the current field's value is less than or equal to the param's value.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func HasMaxOf(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ return IsLte(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param)
+}
+
+// IsTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsTCP4AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ if !isIP4Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) {
+ return false
+ }
+
+ _, err := net.ResolveTCPAddr("tcp4", field.String())
+ return err == nil
+}
+
+// IsTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsTCP6AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ if !isIP6Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) {
+ return false
+ }
+
+ _, err := net.ResolveTCPAddr("tcp6", field.String())
+ return err == nil
+}
+
+// IsTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsTCPAddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ if !isIP4Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) &&
+ !isIP6Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) {
+ return false
+ }
+
+ _, err := net.ResolveTCPAddr("tcp", field.String())
+ return err == nil
+}
+
+// IsUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsUDP4AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ if !isIP4Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) {
+ return false
+ }
+
+ _, err := net.ResolveUDPAddr("udp4", field.String())
+ return err == nil
+}
+
+// IsUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsUDP6AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ if !isIP6Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) {
+ return false
+ }
+
+ _, err := net.ResolveUDPAddr("udp6", field.String())
+ return err == nil
+}
+
+// IsUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsUDPAddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ if !isIP4Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) &&
+ !isIP6Addr(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) {
+ return false
+ }
+
+ _, err := net.ResolveUDPAddr("udp", field.String())
+ return err == nil
+}
+
+// IsIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsIP4AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ if !IsIPv4(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) {
+ return false
+ }
+
+ _, err := net.ResolveIPAddr("ip4", field.String())
+ return err == nil
+}
+
+// IsIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsIP6AddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ if !IsIPv6(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) {
+ return false
+ }
+
+ _, err := net.ResolveIPAddr("ip6", field.String())
+ return err == nil
+}
+
+// IsIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsIPAddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ if !IsIP(v, topStruct, currentStructOrField, field, fieldType, fieldKind, param) {
+ return false
+ }
+
+ _, err := net.ResolveIPAddr("ip", field.String())
+ return err == nil
+}
+
+// IsUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address.
+// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
+func IsUnixAddrResolvable(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ _, err := net.ResolveUnixAddr("unix", field.String())
+ return err == nil
+}
+
+func isIP4Addr(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ val := field.String()
+
+ if idx := strings.LastIndex(val, ":"); idx != -1 {
+ val = val[0:idx]
+ }
+
+ if !IsIPv4(v, topStruct, currentStructOrField, reflect.ValueOf(val), fieldType, fieldKind, param) {
+ return false
+ }
+
+ return true
+}
+
+func isIP6Addr(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+ val := field.String()
+
+ if idx := strings.LastIndex(val, ":"); idx != -1 {
+ if idx != 0 && val[idx-1:idx] == "]" {
+ val = val[1 : idx-1]
+ }
+ }
+
+ if !IsIPv6(v, topStruct, currentStructOrField, reflect.ValueOf(val), fieldType, fieldKind, param) {
+ return false
+ }
+
+ return true
+}
diff --git a/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/cache.go b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/cache.go
new file mode 100644
index 0000000..b3a8720
--- /dev/null
+++ b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/cache.go
@@ -0,0 +1,285 @@
+package validator
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+ "sync"
+ "sync/atomic"
+)
+
+type tagType uint8
+
+const (
+ typeDefault tagType = iota
+ typeOmitEmpty
+ typeNoStructLevel
+ typeStructOnly
+ typeDive
+ typeOr
+ typeExists
+)
+
+type structCache struct {
+ lock sync.Mutex
+ m atomic.Value // map[reflect.Type]*cStruct
+}
+
+func (sc *structCache) Get(key reflect.Type) (c *cStruct, found bool) {
+ c, found = sc.m.Load().(map[reflect.Type]*cStruct)[key]
+ return
+}
+
+func (sc *structCache) Set(key reflect.Type, value *cStruct) {
+
+ m := sc.m.Load().(map[reflect.Type]*cStruct)
+
+ nm := make(map[reflect.Type]*cStruct, len(m)+1)
+ for k, v := range m {
+ nm[k] = v
+ }
+ nm[key] = value
+ sc.m.Store(nm)
+}
+
+type tagCache struct {
+ lock sync.Mutex
+ m atomic.Value // map[string]*cTag
+}
+
+func (tc *tagCache) Get(key string) (c *cTag, found bool) {
+ c, found = tc.m.Load().(map[string]*cTag)[key]
+ return
+}
+
+func (tc *tagCache) Set(key string, value *cTag) {
+
+ m := tc.m.Load().(map[string]*cTag)
+
+ nm := make(map[string]*cTag, len(m)+1)
+ for k, v := range m {
+ nm[k] = v
+ }
+ nm[key] = value
+ tc.m.Store(nm)
+}
+
+type cStruct struct {
+ Name string //结构体名称
+ fields map[int]*cField //结构体对应的字段map
+ fn StructLevelFunc //结构体校验器 (结构体类型->结构体校验器)
+}
+
+type cField struct {
+ Idx int //字段下标
+ Name string //字段名
+ AltName string //
+ cTags *cTag //Field对应的cTag规则,是一个链表(一串的规则).
+}
+
+type cTag struct {
+ tag string //标签
+ aliasTag string //
+ actualAliasTag string //
+ param string //如果是比较类型的标签,这里存放的是比较的值,比如说 min=10,这里存放的是【10】这个值
+ hasAlias bool //是否有别名校验器标签
+ typeof tagType //对应的tagType
+ hasTag bool //是否存在tag标签
+ fn Func //当前cTag对应的【tag标签校验器】
+ next *cTag //下一个cTag标签
+}
+
+func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStruct {
+
+ v.structCache.lock.Lock()
+ defer v.structCache.lock.Unlock() // leave as defer! because if inner panics, it will never get unlocked otherwise!
+
+ typ := current.Type()
+
+ // could have been multiple trying to access, but once first is done this ensures struct
+ // isn't parsed again.
+ //read note 从缓存里面获取对应结构体类型的处理.
+ cs, ok := v.structCache.Get(typ)
+ if ok {
+ return cs
+ }
+
+ //read note 如果缓存里面拿不到的话,就要从结构的Field中去解析
+ cs = &cStruct{Name: sName, fields: make(map[int]*cField), fn: v.structLevelFuncs[typ]}
+
+ numFields := current.NumField()
+
+ var ctag *cTag
+ var fld reflect.StructField
+ var tag string
+ var customName string
+
+ //read note 进行字段的处理
+ for i := 0; i < numFields; i++ {
+
+ fld = typ.Field(i)
+
+ //read note 内嵌类型和小写的处理,直接pass
+ // 类似这种的:
+ /* type Derive struct {
+ Base ---内嵌
+ }
+ */
+ if !fld.Anonymous && fld.PkgPath != blank {
+ continue
+ }
+
+ //read note 获取tag(通过之前Config设置的【tagName】属性去获取对应的tag)
+ tag = fld.Tag.Get(v.tagName)
+
+ //read note 如果是忽略【-】的话,跳过
+ if tag == skipValidationTag {
+ continue
+ }
+
+ customName = fld.Name
+
+ //read note config中【fieldNameTag】的处理,会设置到【cField】的【AltName】字段上,应该只是错误输出用的
+ if v.fieldNameTag != blank {
+
+ name := strings.SplitN(fld.Tag.Get(v.fieldNameTag), ",", 2)[0]
+
+ // dash check is for json "-" (aka skipValidationTag) means don't output in json
+ if name != "" && name != skipValidationTag {
+ customName = name
+ }
+ }
+
+ // NOTE: cannot use shared tag cache, because tags may be equal, but things like alias may be different
+ // and so only struct level caching can be used instead of combined with Field tag caching
+
+ //read note struct层的校验规则和Field层的校验规则不能共用(标签可能相同,但是别名会不一样..)
+
+ if len(tag) > 0 {
+ ctag, _ = v.parseFieldTagsRecursive(tag, fld.Name, blank, false)
+ } else {
+ // even if field doesn't have validations need cTag for traversing to potential inner/nested
+ // elements of the field.
+ ctag = new(cTag)
+ }
+
+ cs.fields[i] = &cField{Idx: i, Name: fld.Name, AltName: customName, cTags: ctag}
+ }
+
+ v.structCache.Set(typ, cs)
+
+ return cs
+}
+
+func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias string, hasAlias bool) (firstCtag *cTag, current *cTag) {
+
+ var t string
+ var ok bool
+ noAlias := len(alias) == 0
+ //read note:这边会把tag根据【,】进行分割处理,得到对应的tag组,所以我们在写的时候可以写入,分割的标签
+ tags := strings.Split(tag, tagSeparator)
+
+ for i := 0; i < len(tags); i++ {
+
+ t = tags[i]
+
+ if noAlias {
+ alias = t
+ }
+
+ //read note 如果有别名校验器,则回去查找别名校验器(第一个和后面的设置不一样.调用next和没有调用next的区别)
+ if v.hasAliasValidators {
+ // check map for alias and process new tags, otherwise process as usual
+ if tagsVal, found := v.aliasValidators[t]; found {
+
+ if i == 0 {
+ //read note 对别名校验器进行解析(一个子递归的过程.)除第一个校验器外,后面的校验器是通过一个next指向的链表连接起来
+ firstCtag, current = v.parseFieldTagsRecursive(tagsVal, fieldName, t, true)
+ } else {
+ next, curr := v.parseFieldTagsRecursive(tagsVal, fieldName, t, true)
+ current.next, current = next, curr
+
+ }
+
+ continue
+ }
+ }
+
+ //read note 设置对应的默认标签(第一个和后面的设置不一样.调用next和没有调用next的区别)
+ if i == 0 {
+ current = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true}
+ firstCtag = current
+ } else {
+ current.next = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true}
+ current = current.next
+ }
+
+ //read note 判断用 【,】分割后的标签,前面几个是处理特殊标签的.如果不是特殊标签,则往下处理设置tag的值
+ switch t {
+ case diveTag:
+ current.typeof = typeDive
+ continue
+
+ case omitempty:
+ current.typeof = typeOmitEmpty
+ continue
+
+ case structOnlyTag:
+ current.typeof = typeStructOnly
+ continue
+
+ case noStructLevelTag:
+ current.typeof = typeNoStructLevel
+ continue
+
+ case existsTag:
+ current.typeof = typeExists
+ continue
+
+ default:
+ // if a pipe character is needed within the param you must use the utf8Pipe representation "0x7C"
+ orVals := strings.Split(t, orSeparator)
+
+ //read note 或的条件进行拆分.
+
+ for j := 0; j < len(orVals); j++ {
+ //read note 解析【=】标签
+ vals := strings.SplitN(orVals[j], tagKeySeparator, 2)
+
+ if noAlias {
+ alias = vals[0]
+ current.aliasTag = alias
+ } else {
+ current.actualAliasTag = t
+ }
+
+ //read note 如果或的标签成立,也就是说 A|B|C ABC会组装成一个链(非头节点需要往下一个节点去处理,所以这边需要把current指向它的next)
+ if j > 0 {
+ current.next = &cTag{aliasTag: alias, actualAliasTag: current.actualAliasTag, hasAlias: hasAlias, hasTag: true}
+ current = current.next
+ }
+
+ current.tag = vals[0]
+ if len(current.tag) == 0 {
+ panic(strings.TrimSpace(fmt.Sprintf(invalidValidation, fieldName)))
+ }
+
+ //read note 查找对应的校验规则
+ if current.fn, ok = v.validationFuncs[current.tag]; !ok {
+ panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, fieldName)))
+ }
+
+ //read note 设置为typeOr.这个应该在后面处理对应字段的时候会拿到并且通过or的方式进行处理
+ if len(orVals) > 1 {
+ current.typeof = typeOr
+ }
+
+ if len(vals) > 1 {
+ current.param = strings.Replace(strings.Replace(vals[1], utf8HexComma, ",", -1), utf8Pipe, "|", -1)
+ }
+ }
+ }
+ }
+
+ return
+}
diff --git a/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/doc.go b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/doc.go
new file mode 100644
index 0000000..fdede2c
--- /dev/null
+++ b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/doc.go
@@ -0,0 +1,852 @@
+/*
+Package validator implements value validations for structs and individual fields
+based on tags.
+
+It can also handle Cross-Field and Cross-Struct validation for nested structs
+and has the ability to dive into arrays and maps of any type.
+
+Why not a better error message?
+Because this library intends for you to handle your own error messages.
+
+Why should I handle my own errors?
+Many reasons. We built an internationalized application and needed to know the
+field, and what validation failed so we could provide a localized error.
+
+ if fieldErr.Field == "Name" {
+ switch fieldErr.ErrorTag
+ case "required":
+ return "Translated string based on field + error"
+ default:
+ return "Translated string based on field"
+ }
+
+
+Validation Functions Return Type error
+
+Doing things this way is actually the way the standard library does, see the
+file.Open method here:
+
+ https://golang.org/pkg/os/#Open.
+
+The authors return type "error" to avoid the issue discussed in the following,
+where err is always != nil:
+
+ http://stackoverflow.com/a/29138676/3158232
+ https://github.com/go-playground/validator/issues/134
+
+Validator only returns nil or ValidationErrors as type error; so, in your code
+all you need to do is check if the error returned is not nil, and if it's not
+type cast it to type ValidationErrors like so err.(validator.ValidationErrors).
+
+Custom Functions
+
+Custom functions can be added. Example:
+
+ // Structure
+ func customFunc(v *Validate, topStruct reflect.Value, currentStructOrField reflect.Value, field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string) bool {
+
+ if whatever {
+ return false
+ }
+
+ return true
+ }
+
+ validate.RegisterValidation("custom tag name", customFunc)
+ // NOTES: using the same tag name as an existing function
+ // will overwrite the existing one
+
+Cross-Field Validation
+
+Cross-Field Validation can be done via the following tags:
+ - eqfield
+ - nefield
+ - gtfield
+ - gtefield
+ - ltfield
+ - ltefield
+ - eqcsfield
+ - necsfield
+ - gtcsfield
+ - ftecsfield
+ - ltcsfield
+ - ltecsfield
+
+If, however, some custom cross-field validation is required, it can be done
+using a custom validation.
+
+Why not just have cross-fields validation tags (i.e. only eqcsfield and not
+eqfield)?
+
+The reason is efficiency. If you want to check a field within the same struct
+"eqfield" only has to find the field on the same struct (1 level). But, if we
+used "eqcsfield" it could be multiple levels down. Example:
+
+ type Inner struct {
+ StartDate time.Time
+ }
+
+ type Outer struct {
+ InnerStructField *Inner
+ CreatedAt time.Time `validate:"ltecsfield=InnerStructField.StartDate"`
+ }
+
+ now := time.Now()
+
+ inner := &Inner{
+ StartDate: now,
+ }
+
+ outer := &Outer{
+ InnerStructField: inner,
+ CreatedAt: now,
+ }
+
+ errs := validate.Struct(outer)
+
+ // NOTE: when calling validate.Struct(val) topStruct will be the top level struct passed
+ // into the function
+ // when calling validate.FieldWithValue(val, field, tag) val will be
+ // whatever you pass, struct, field...
+ // when calling validate.Field(field, tag) val will be nil
+
+Multiple Validators
+
+Multiple validators on a field will process in the order defined. Example:
+
+ type Test struct {
+ Field `validate:"max=10,min=1"`
+ }
+
+ // max will be checked then min
+
+Bad Validator definitions are not handled by the library. Example:
+
+ type Test struct {
+ Field `validate:"min=10,max=0"`
+ }
+
+ // this definition of min max will never succeed
+
+Using Validator Tags
+
+Baked In Cross-Field validation only compares fields on the same struct.
+If Cross-Field + Cross-Struct validation is needed you should implement your
+own custom validator.
+
+Comma (",") is the default separator of validation tags. If you wish to
+have a comma included within the parameter (i.e. excludesall=,) you will need to
+use the UTF-8 hex representation 0x2C, which is replaced in the code as a comma,
+so the above will become excludesall=0x2C.
+
+ type Test struct {
+ Field `validate:"excludesall=,"` // BAD! Do not include a comma.
+ Field `validate:"excludesall=0x2C"` // GOOD! Use the UTF-8 hex representation.
+ }
+
+Pipe ("|") is the default separator of validation tags. If you wish to
+have a pipe included within the parameter i.e. excludesall=| you will need to
+use the UTF-8 hex representation 0x7C, which is replaced in the code as a pipe,
+so the above will become excludesall=0x7C
+
+ type Test struct {
+ Field `validate:"excludesall=|"` // BAD! Do not include a a pipe!
+ Field `validate:"excludesall=0x7C"` // GOOD! Use the UTF-8 hex representation.
+ }
+
+
+Baked In Validators and Tags
+
+Here is a list of the current built in validators:
+
+
+Skip Field
+
+Tells the validation to skip this struct field; this is particularly
+handy in ignoring embedded structs from being validated. (Usage: -)
+ Usage: -
+
+
+Or Operator
+
+This is the 'or' operator allowing multiple validators to be used and
+accepted. (Usage: rbg|rgba) <-- this would allow either rgb or rgba
+colors to be accepted. This can also be combined with 'and' for example
+( Usage: omitempty,rgb|rgba)
+
+ Usage: |
+
+StructOnly
+
+When a field that is a nested struct is encountered, and contains this flag
+any validation on the nested struct will be run, but none of the nested
+struct fields will be validated. This is usefull if inside of you program
+you know the struct will be valid, but need to verify it has been assigned.
+NOTE: only "required" and "omitempty" can be used on a struct itself.
+
+ Usage: structonly
+
+NoStructLevel
+
+Same as structonly tag except that any struct level validations will not run.
+
+ Usage: nostructlevel
+
+Exists
+
+Is a special tag without a validation function attached. It is used when a field
+is a Pointer, Interface or Invalid and you wish to validate that it exists.
+Example: want to ensure a bool exists if you define the bool as a pointer and
+use exists it will ensure there is a value; couldn't use required as it would
+fail when the bool was false. exists will fail is the value is a Pointer, Interface
+or Invalid and is nil.
+
+ Usage: exists
+
+Omit Empty
+
+Allows conditional validation, for example if a field is not set with
+a value (Determined by the "required" validator) then other validation
+such as min or max won't run, but if a value is set validation will run.
+
+ Usage: omitempty
+
+Dive
+
+This tells the validator to dive into a slice, array or map and validate that
+level of the slice, array or map with the validation tags that follow.
+Multidimensional nesting is also supported, each level you wish to dive will
+require another dive tag.
+
+ Usage: dive
+
+Example #1
+
+ [][]string with validation tag "gt=0,dive,len=1,dive,required"
+ // gt=0 will be applied to []
+ // len=1 will be applied to []string
+ // required will be applied to string
+
+Example #2
+
+ [][]string with validation tag "gt=0,dive,dive,required"
+ // gt=0 will be applied to []
+ // []string will be spared validation
+ // required will be applied to string
+
+Required
+
+This validates that the value is not the data types default zero value.
+For numbers ensures value is not zero. For strings ensures value is
+not "". For slices, maps, pointers, interfaces, channels and functions
+ensures the value is not nil.
+
+ Usage: required
+
+Length
+
+For numbers, max will ensure that the value is
+equal to the parameter given. For strings, it checks that
+the string length is exactly that number of characters. For slices,
+arrays, and maps, validates the number of items.
+
+ Usage: len=10
+
+Maximum
+
+For numbers, max will ensure that the value is
+less than or equal to the parameter given. For strings, it checks
+that the string length is at most that number of characters. For
+slices, arrays, and maps, validates the number of items.
+
+ Usage: max=10
+
+Mininum
+
+For numbers, min will ensure that the value is
+greater or equal to the parameter given. For strings, it checks that
+the string length is at least that number of characters. For slices,
+arrays, and maps, validates the number of items.
+
+ Usage: min=10
+
+Equals
+
+For strings & numbers, eq will ensure that the value is
+equal to the parameter given. For slices, arrays, and maps,
+validates the number of items.
+
+ Usage: eq=10
+
+Not Equal
+
+For strings & numbers, ne will ensure that the value is not
+equal to the parameter given. For slices, arrays, and maps,
+validates the number of items.
+
+ Usage: ne=10
+
+Greater Than
+
+For numbers, this will ensure that the value is greater than the
+parameter given. For strings, it checks that the string length
+is greater than that number of characters. For slices, arrays
+and maps it validates the number of items.
+
+Example #1
+
+ Usage: gt=10
+
+Example #2 (time.Time)
+
+For time.Time ensures the time value is greater than time.Now.UTC().
+
+ Usage: gt
+
+Greater Than or Equal
+
+Same as 'min' above. Kept both to make terminology with 'len' easier.
+
+
+Example #1
+
+ Usage: gte=10
+
+Example #2 (time.Time)
+
+For time.Time ensures the time value is greater than or equal to time.Now.UTC().
+
+ Usage: gte
+
+Less Than
+
+For numbers, this will ensure that the value is less than the parameter given.
+For strings, it checks that the string length is less than that number of
+characters. For slices, arrays, and maps it validates the number of items.
+
+Example #1
+
+ Usage: lt=10
+
+Example #2 (time.Time)
+For time.Time ensures the time value is less than time.Now.UTC().
+
+ Usage: lt
+
+Less Than or Equal
+
+Same as 'max' above. Kept both to make terminology with 'len' easier.
+
+Example #1
+
+ Usage: lte=10
+
+Example #2 (time.Time)
+
+For time.Time ensures the time value is less than or equal to time.Now.UTC().
+
+ Usage: lte
+
+Field Equals Another Field
+
+This will validate the field value against another fields value either within
+a struct or passed in field.
+
+Example #1:
+
+ // Validation on Password field using:
+ Usage: eqfield=ConfirmPassword
+
+Example #2:
+
+ // Validating by field:
+ validate.FieldWithValue(password, confirmpassword, "eqfield")
+
+Field Equals Another Field (relative)
+
+This does the same as eqfield except that it validates the field provided relative
+to the top level struct.
+
+ Usage: eqcsfield=InnerStructField.Field)
+
+Field Does Not Equal Another Field
+
+This will validate the field value against another fields value either within
+a struct or passed in field.
+
+Examples:
+
+ // Confirm two colors are not the same:
+ //
+ // Validation on Color field:
+ Usage: nefield=Color2
+
+ // Validating by field:
+ validate.FieldWithValue(color1, color2, "nefield")
+
+Field Does Not Equal Another Field (relative)
+
+This does the same as nefield except that it validates the field provided
+relative to the top level struct.
+
+ Usage: necsfield=InnerStructField.Field
+
+Field Greater Than Another Field
+
+Only valid for Numbers and time.Time types, this will validate the field value
+against another fields value either within a struct or passed in field.
+usage examples are for validation of a Start and End date:
+
+Example #1:
+
+ // Validation on End field using:
+ validate.Struct Usage(gtfield=Start)
+
+Example #2:
+
+ // Validating by field:
+ validate.FieldWithValue(start, end, "gtfield")
+
+
+Field Greater Than Another Relative Field
+
+This does the same as gtfield except that it validates the field provided
+relative to the top level struct.
+
+ Usage: gtcsfield=InnerStructField.Field
+
+Field Greater Than or Equal To Another Field
+
+Only valid for Numbers and time.Time types, this will validate the field value
+against another fields value either within a struct or passed in field.
+usage examples are for validation of a Start and End date:
+
+Example #1:
+
+ // Validation on End field using:
+ validate.Struct Usage(gtefield=Start)
+
+Example #2:
+
+ // Validating by field:
+ validate.FieldWithValue(start, end, "gtefield")
+
+Field Greater Than or Equal To Another Relative Field
+
+This does the same as gtefield except that it validates the field provided relative
+to the top level struct.
+
+ Usage: gtecsfield=InnerStructField.Field
+
+Less Than Another Field
+
+Only valid for Numbers and time.Time types, this will validate the field value
+against another fields value either within a struct or passed in field.
+usage examples are for validation of a Start and End date:
+
+Example #1:
+
+ // Validation on End field using:
+ validate.Struct Usage(ltfield=Start)
+
+Example #2:
+
+ // Validating by field:
+ validate.FieldWithValue(start, end, "ltfield")
+
+Less Than Another Relative Field
+
+This does the same as ltfield except that it validates the field provided relative
+to the top level struct.
+
+ Usage: ltcsfield=InnerStructField.Field
+
+Less Than or Equal To Another Field
+
+Only valid for Numbers and time.Time types, this will validate the field value
+against another fields value either within a struct or passed in field.
+usage examples are for validation of a Start and End date:
+
+Example #1:
+
+ // Validation on End field using:
+ validate.Struct Usage(ltefield=Start)
+
+Example #2:
+
+ // Validating by field:
+ validate.FieldWithValue(start, end, "ltefield")
+
+Less Than or Equal To Another Relative Field
+
+This does the same as ltefield except that it validates the field provided relative
+to the top level struct.
+
+ Usage: ltecsfield=InnerStructField.Field
+
+Alpha Only
+
+This validates that a string value contains alpha characters only
+
+ Usage: alpha
+
+Alphanumeric
+
+This validates that a string value contains alphanumeric characters only
+
+ Usage: alphanum
+
+Numeric
+
+This validates that a string value contains a basic numeric value.
+basic excludes exponents etc...
+
+ Usage: numeric
+
+Hexadecimal String
+
+This validates that a string value contains a valid hexadecimal.
+
+ Usage: hexadecimal
+
+Hexcolor String
+
+This validates that a string value contains a valid hex color including
+hashtag (#)
+
+ Usage: hexcolor
+
+RGB String
+
+This validates that a string value contains a valid rgb color
+
+ Usage: rgb
+
+RGBA String
+
+This validates that a string value contains a valid rgba color
+
+ Usage: rgba
+
+HSL String
+
+This validates that a string value contains a valid hsl color
+
+ Usage: hsl
+
+HSLA String
+
+This validates that a string value contains a valid hsla color
+
+ Usage: hsla
+
+E-mail String
+
+This validates that a string value contains a valid email
+This may not conform to all possibilities of any rfc standard, but neither
+does any email provider accept all posibilities.
+
+ Usage: email
+
+URL String
+
+This validates that a string value contains a valid url
+This will accept any url the golang request uri accepts but must contain
+a schema for example http:// or rtmp://
+
+ Usage: url
+
+URI String
+
+This validates that a string value contains a valid uri
+This will accept any uri the golang request uri accepts
+
+ Usage: uri
+
+Base64 String
+
+This validates that a string value contains a valid base64 value.
+Although an empty string is valid base64 this will report an empty string
+as an error, if you wish to accept an empty string as valid you can use
+this with the omitempty tag.
+
+ Usage: base64
+
+Contains
+
+This validates that a string value contains the substring value.
+
+ Usage: contains=@
+
+Contains Any
+
+This validates that a string value contains any Unicode code points
+in the substring value.
+
+ Usage: containsany=!@#?
+
+Contains Rune
+
+This validates that a string value contains the supplied rune value.
+
+ Usage: containsrune=@
+
+Excludes
+
+This validates that a string value does not contain the substring value.
+
+ Usage: excludes=@
+
+Excludes All
+
+This validates that a string value does not contain any Unicode code
+points in the substring value.
+
+ Usage: excludesall=!@#?
+
+Excludes Rune
+
+This validates that a string value does not contain the supplied rune value.
+
+ Usage: excludesrune=@
+
+International Standard Book Number
+
+This validates that a string value contains a valid isbn10 or isbn13 value.
+
+ Usage: isbn
+
+International Standard Book Number 10
+
+This validates that a string value contains a valid isbn10 value.
+
+ Usage: isbn10
+
+International Standard Book Number 13
+
+This validates that a string value contains a valid isbn13 value.
+
+ Usage: isbn13
+
+
+Universally Unique Identifier UUID
+
+This validates that a string value contains a valid UUID.
+
+ Usage: uuid
+
+Universally Unique Identifier UUID v3
+
+This validates that a string value contains a valid version 3 UUID.
+
+ Usage: uuid3
+
+Universally Unique Identifier UUID v4
+
+This validates that a string value contains a valid version 4 UUID.
+
+ Usage: uuid4
+
+Universally Unique Identifier UUID v5
+
+This validates that a string value contains a valid version 5 UUID.
+
+ Usage: uuid5
+
+ASCII
+
+This validates that a string value contains only ASCII characters.
+NOTE: if the string is blank, this validates as true.
+
+ Usage: ascii
+
+Printable ASCII
+
+This validates that a string value contains only printable ASCII characters.
+NOTE: if the string is blank, this validates as true.
+
+ Usage: asciiprint
+
+Multi-Byte Characters
+
+This validates that a string value contains one or more multibyte characters.
+NOTE: if the string is blank, this validates as true.
+
+ Usage: multibyte
+
+Data URL
+
+This validates that a string value contains a valid DataURI.
+NOTE: this will also validate that the data portion is valid base64
+
+ Usage: datauri
+
+Latitude
+
+This validates that a string value contains a valid latitude.
+
+ Usage: latitude
+
+Longitude
+
+This validates that a string value contains a valid longitude.
+
+ Usage: longitude
+
+Social Security Number SSN
+
+This validates that a string value contains a valid U.S. Social Security Number.
+
+ Usage: ssn
+
+Internet Protocol Address IP
+
+This validates that a string value contains a valid IP Adress.
+
+ Usage: ip
+
+Internet Protocol Address IPv4
+
+This validates that a string value contains a valid v4 IP Adress.
+
+ Usage: ipv4
+
+Internet Protocol Address IPv6
+
+This validates that a string value contains a valid v6 IP Adress.
+
+ Usage: ipv6
+
+Classless Inter-Domain Routing CIDR
+
+This validates that a string value contains a valid CIDR Adress.
+
+ Usage: cidr
+
+Classless Inter-Domain Routing CIDRv4
+
+This validates that a string value contains a valid v4 CIDR Adress.
+
+ Usage: cidrv4
+
+Classless Inter-Domain Routing CIDRv6
+
+This validates that a string value contains a valid v6 CIDR Adress.
+
+ Usage: cidrv6
+
+Transmission Control Protocol Address TCP
+
+This validates that a string value contains a valid resolvable TCP Adress.
+
+ Usage: tcp_addr
+
+Transmission Control Protocol Address TCPv4
+
+This validates that a string value contains a valid resolvable v4 TCP Adress.
+
+ Usage: tcp4_addr
+
+Transmission Control Protocol Address TCPv6
+
+This validates that a string value contains a valid resolvable v6 TCP Adress.
+
+ Usage: tcp6_addr
+
+User Datagram Protocol Address UDP
+
+This validates that a string value contains a valid resolvable UDP Adress.
+
+ Usage: udp_addr
+
+User Datagram Protocol Address UDPv4
+
+This validates that a string value contains a valid resolvable v4 UDP Adress.
+
+ Usage: udp4_addr
+
+User Datagram Protocol Address UDPv6
+
+This validates that a string value contains a valid resolvable v6 UDP Adress.
+
+ Usage: udp6_addr
+
+Internet Protocol Address IP
+
+This validates that a string value contains a valid resolvable IP Adress.
+
+ Usage: ip_addr
+
+Internet Protocol Address IPv4
+
+This validates that a string value contains a valid resolvable v4 IP Adress.
+
+ Usage: ip4_addr
+
+Internet Protocol Address IPv6
+
+This validates that a string value contains a valid resolvable v6 IP Adress.
+
+ Usage: ip6_addr
+
+Unix domain socket end point Address
+
+This validates that a string value contains a valid Unix Adress.
+
+ Usage: unix_addr
+
+Media Access Control Address MAC
+
+This validates that a string value contains a valid MAC Adress.
+
+ Usage: mac
+
+Note: See Go's ParseMAC for accepted formats and types:
+
+ http://golang.org/src/net/mac.go?s=866:918#L29
+
+Alias Validators and Tags
+
+NOTE: When returning an error, the tag returned in "FieldError" will be
+the alias tag unless the dive tag is part of the alias. Everything after the
+dive tag is not reported as the alias tag. Also, the "ActualTag" in the before
+case will be the actual tag within the alias that failed.
+
+Here is a list of the current built in alias tags:
+
+ "iscolor"
+ alias is "hexcolor|rgb|rgba|hsl|hsla" (Usage: iscolor)
+
+Validator notes:
+
+ regex
+ a regex validator won't be added because commas and = signs can be part
+ of a regex which conflict with the validation definitions. Although
+ workarounds can be made, they take away from using pure regex's.
+ Furthermore it's quick and dirty but the regex's become harder to
+ maintain and are not reusable, so it's as much a programming philosiphy
+ as anything.
+
+ In place of this new validator functions should be created; a regex can
+ be used within the validator function and even be precompiled for better
+ efficiency within regexes.go.
+
+ And the best reason, you can submit a pull request and we can keep on
+ adding to the validation library of this package!
+
+Panics
+
+This package panics when bad input is provided, this is by design, bad code like
+that should not make it to production.
+
+ type Test struct {
+ TestField string `validate:"nonexistantfunction=1"`
+ }
+
+ t := &Test{
+ TestField: "Test"
+ }
+
+ validate.Struct(t) // this will panic
+*/
+package validator
diff --git a/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/logo.png b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/logo.png
new file mode 100644
index 0000000..355000f
Binary files /dev/null and b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/logo.png differ
diff --git a/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/regexes.go b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/regexes.go
new file mode 100644
index 0000000..83ae198
--- /dev/null
+++ b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/regexes.go
@@ -0,0 +1,59 @@
+package validator
+
+import "regexp"
+
+const (
+ alphaRegexString = "^[a-zA-Z]+$"
+ alphaNumericRegexString = "^[a-zA-Z0-9]+$"
+ numericRegexString = "^[-+]?[0-9]+(?:\\.[0-9]+)?$"
+ numberRegexString = "^[0-9]+$"
+ hexadecimalRegexString = "^[0-9a-fA-F]+$"
+ hexcolorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"
+ rgbRegexString = "^rgb\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*\\)$"
+ rgbaRegexString = "^rgba\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])|(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%\\s*,\\s*(?:0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])%)\\s*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$"
+ hslRegexString = "^hsl\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*\\)$"
+ hslaRegexString = "^hsla\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d|3[0-5]\\d|360)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0|[1-9]\\d?|100)%)\\s*,\\s*(?:(?:0.[1-9]*)|[01])\\s*\\)$"
+ emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:\\(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22)))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$"
+ base64RegexString = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$"
+ iSBN10RegexString = "^(?:[0-9]{9}X|[0-9]{10})$"
+ iSBN13RegexString = "^(?:(?:97(?:8|9))[0-9]{10})$"
+ uUID3RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$"
+ uUID4RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
+ uUID5RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
+ uUIDRegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
+ aSCIIRegexString = "^[\x00-\x7F]*$"
+ printableASCIIRegexString = "^[\x20-\x7E]*$"
+ multibyteRegexString = "[^\x00-\x7F]"
+ dataURIRegexString = "^data:.+\\/(.+);base64$"
+ latitudeRegexString = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$"
+ longitudeRegexString = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$"
+ sSNRegexString = `^\d{3}[- ]?\d{2}[- ]?\d{4}$`
+)
+
+var (
+ alphaRegex = regexp.MustCompile(alphaRegexString)
+ alphaNumericRegex = regexp.MustCompile(alphaNumericRegexString)
+ numericRegex = regexp.MustCompile(numericRegexString)
+ numberRegex = regexp.MustCompile(numberRegexString)
+ hexadecimalRegex = regexp.MustCompile(hexadecimalRegexString)
+ hexcolorRegex = regexp.MustCompile(hexcolorRegexString)
+ rgbRegex = regexp.MustCompile(rgbRegexString)
+ rgbaRegex = regexp.MustCompile(rgbaRegexString)
+ hslRegex = regexp.MustCompile(hslRegexString)
+ hslaRegex = regexp.MustCompile(hslaRegexString)
+ emailRegex = regexp.MustCompile(emailRegexString)
+ base64Regex = regexp.MustCompile(base64RegexString)
+ iSBN10Regex = regexp.MustCompile(iSBN10RegexString)
+ iSBN13Regex = regexp.MustCompile(iSBN13RegexString)
+ uUID3Regex = regexp.MustCompile(uUID3RegexString)
+ uUID4Regex = regexp.MustCompile(uUID4RegexString)
+ uUID5Regex = regexp.MustCompile(uUID5RegexString)
+ uUIDRegex = regexp.MustCompile(uUIDRegexString)
+ aSCIIRegex = regexp.MustCompile(aSCIIRegexString)
+ printableASCIIRegex = regexp.MustCompile(printableASCIIRegexString)
+ multibyteRegex = regexp.MustCompile(multibyteRegexString)
+ dataURIRegex = regexp.MustCompile(dataURIRegexString)
+ latitudeRegex = regexp.MustCompile(latitudeRegexString)
+ longitudeRegex = regexp.MustCompile(longitudeRegexString)
+ sSNRegex = regexp.MustCompile(sSNRegexString)
+)
diff --git a/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/util.go b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/util.go
new file mode 100644
index 0000000..08f691c
--- /dev/null
+++ b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/util.go
@@ -0,0 +1,253 @@
+package validator
+
+import (
+ "reflect"
+ "strconv"
+ "strings"
+)
+
+const (
+ blank = ""
+ namespaceSeparator = "."
+ leftBracket = "["
+ rightBracket = "]"
+ restrictedTagChars = ".[],|=+()`~!@#$%^&*\\\"/?<>{}"
+ restrictedAliasErr = "Alias '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation"
+ restrictedTagErr = "Tag '%s' either contains restricted characters or is the same as a restricted tag needed for normal operation"
+)
+
+var (
+ restrictedTags = map[string]struct{}{
+ diveTag: {},
+ existsTag: {},
+ structOnlyTag: {},
+ omitempty: {},
+ skipValidationTag: {},
+ utf8HexComma: {},
+ utf8Pipe: {},
+ noStructLevelTag: {},
+ }
+)
+
+// ExtractType gets the actual underlying type of field value.
+// It will dive into pointers, customTypes and return you the
+// underlying value and it's kind.
+// it is exposed for use within you Custom Functions
+func (v *Validate) ExtractType(current reflect.Value) (reflect.Value, reflect.Kind) {
+
+ val, k, _ := v.extractTypeInternal(current, false)
+ return val, k
+}
+
+// only exists to not break backward compatibility, needed to return the third param for a bug fix internally
+func (v *Validate) extractTypeInternal(current reflect.Value, nullable bool) (reflect.Value, reflect.Kind, bool) {
+
+ switch current.Kind() {
+ case reflect.Ptr:
+
+ nullable = true
+
+ if current.IsNil() {
+ return current, reflect.Ptr, nullable
+ }
+
+ return v.extractTypeInternal(current.Elem(), nullable)
+
+ case reflect.Interface:
+
+ nullable = true
+
+ if current.IsNil() {
+ return current, reflect.Interface, nullable
+ }
+
+ return v.extractTypeInternal(current.Elem(), nullable)
+
+ case reflect.Invalid:
+ return current, reflect.Invalid, nullable
+
+ default:
+
+ if v.hasCustomFuncs {
+
+ if fn, ok := v.customTypeFuncs[current.Type()]; ok {
+ //read note 如果有自定义的类型校验器,则这边会先去调用一下类型校验器,然后在返回对应的结构体值,继续往回上一层,往下校验
+ return v.extractTypeInternal(reflect.ValueOf(fn(current)), nullable)
+ }
+ }
+
+ return current, current.Kind(), nullable
+ }
+}
+
+// GetStructFieldOK traverses a struct to retrieve a specific field denoted by the provided namespace and
+// returns the field, field kind and whether is was successful in retrieving the field at all.
+// NOTE: when not successful ok will be false, this can happen when a nested struct is nil and so the field
+// could not be retrieved because it didn't exist.
+func (v *Validate) GetStructFieldOK(current reflect.Value, namespace string) (reflect.Value, reflect.Kind, bool) {
+
+ current, kind := v.ExtractType(current)
+
+ if kind == reflect.Invalid {
+ return current, kind, false
+ }
+
+ if namespace == blank {
+ return current, kind, true
+ }
+
+ switch kind {
+
+ case reflect.Ptr, reflect.Interface:
+
+ return current, kind, false
+
+ case reflect.Struct:
+
+ typ := current.Type()
+ fld := namespace
+ ns := namespace
+
+ if typ != timeType && typ != timePtrType {
+
+ idx := strings.Index(namespace, namespaceSeparator)
+
+ if idx != -1 {
+ fld = namespace[:idx]
+ ns = namespace[idx+1:]
+ } else {
+ ns = blank
+ }
+
+ bracketIdx := strings.Index(fld, leftBracket)
+ if bracketIdx != -1 {
+ fld = fld[:bracketIdx]
+
+ ns = namespace[bracketIdx:]
+ }
+
+ current = current.FieldByName(fld)
+
+ return v.GetStructFieldOK(current, ns)
+ }
+
+ case reflect.Array, reflect.Slice:
+ idx := strings.Index(namespace, leftBracket)
+ idx2 := strings.Index(namespace, rightBracket)
+
+ arrIdx, _ := strconv.Atoi(namespace[idx+1 : idx2])
+
+ if arrIdx >= current.Len() {
+ return current, kind, false
+ }
+
+ startIdx := idx2 + 1
+
+ if startIdx < len(namespace) {
+ if namespace[startIdx:startIdx+1] == namespaceSeparator {
+ startIdx++
+ }
+ }
+
+ return v.GetStructFieldOK(current.Index(arrIdx), namespace[startIdx:])
+
+ case reflect.Map:
+ idx := strings.Index(namespace, leftBracket) + 1
+ idx2 := strings.Index(namespace, rightBracket)
+
+ endIdx := idx2
+
+ if endIdx+1 < len(namespace) {
+ if namespace[endIdx+1:endIdx+2] == namespaceSeparator {
+ endIdx++
+ }
+ }
+
+ key := namespace[idx:idx2]
+
+ switch current.Type().Key().Kind() {
+ case reflect.Int:
+ i, _ := strconv.Atoi(key)
+ return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:])
+ case reflect.Int8:
+ i, _ := strconv.ParseInt(key, 10, 8)
+ return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(int8(i))), namespace[endIdx+1:])
+ case reflect.Int16:
+ i, _ := strconv.ParseInt(key, 10, 16)
+ return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(int16(i))), namespace[endIdx+1:])
+ case reflect.Int32:
+ i, _ := strconv.ParseInt(key, 10, 32)
+ return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(int32(i))), namespace[endIdx+1:])
+ case reflect.Int64:
+ i, _ := strconv.ParseInt(key, 10, 64)
+ return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:])
+ case reflect.Uint:
+ i, _ := strconv.ParseUint(key, 10, 0)
+ return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(uint(i))), namespace[endIdx+1:])
+ case reflect.Uint8:
+ i, _ := strconv.ParseUint(key, 10, 8)
+ return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(uint8(i))), namespace[endIdx+1:])
+ case reflect.Uint16:
+ i, _ := strconv.ParseUint(key, 10, 16)
+ return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(uint16(i))), namespace[endIdx+1:])
+ case reflect.Uint32:
+ i, _ := strconv.ParseUint(key, 10, 32)
+ return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(uint32(i))), namespace[endIdx+1:])
+ case reflect.Uint64:
+ i, _ := strconv.ParseUint(key, 10, 64)
+ return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(i)), namespace[endIdx+1:])
+ case reflect.Float32:
+ f, _ := strconv.ParseFloat(key, 32)
+ return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(float32(f))), namespace[endIdx+1:])
+ case reflect.Float64:
+ f, _ := strconv.ParseFloat(key, 64)
+ return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(f)), namespace[endIdx+1:])
+ case reflect.Bool:
+ b, _ := strconv.ParseBool(key)
+ return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(b)), namespace[endIdx+1:])
+
+ // reflect.Type = string
+ default:
+ return v.GetStructFieldOK(current.MapIndex(reflect.ValueOf(key)), namespace[endIdx+1:])
+ }
+ }
+
+ // if got here there was more namespace, cannot go any deeper
+ panic("Invalid field namespace")
+}
+
+// asInt returns the parameter as a int64
+// or panics if it can't convert
+func asInt(param string) int64 {
+
+ i, err := strconv.ParseInt(param, 0, 64)
+ panicIf(err)
+
+ return i
+}
+
+// asUint returns the parameter as a uint64
+// or panics if it can't convert
+func asUint(param string) uint64 {
+
+ i, err := strconv.ParseUint(param, 0, 64)
+ panicIf(err)
+
+ return i
+}
+
+// asFloat returns the parameter as a float64
+// or panics if it can't convert
+func asFloat(param string) float64 {
+
+ i, err := strconv.ParseFloat(param, 64)
+ panicIf(err)
+
+ return i
+}
+
+func panicIf(err error) {
+ if err != nil {
+ panic(err.Error())
+ }
+}
diff --git a/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/validator.go b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/validator.go
new file mode 100644
index 0000000..fde5326
--- /dev/null
+++ b/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8/validator.go
@@ -0,0 +1,829 @@
+/**
+ * Package validator
+ *
+ * MISC:
+ * - anonymous structs - they don't have names so expect the Struct name within StructErrors to be blank
+ *
+ */
+
+package validator
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "reflect"
+ "strings"
+ "sync"
+ "time"
+)
+
+const (
+ utf8HexComma = "0x2C" //read note 在tag里面代表【,】;需要这么书写,直接写【,】会被识别成分割符
+ utf8Pipe = "0x7C" //read note 在tag里面代表【|】;需要这么书写,直接写【|】会被识别成条件符
+ tagSeparator = "," //read note tag标签分割符
+ orSeparator = "|" //read note tag判断条件【或】
+ tagKeySeparator = "=" //read note tag里面需要等值 使用=
+
+ structOnlyTag = "structonly" //read note 结构体上有的tagType,因为结构体的特殊性,他在获取cTag的时候是从第二个开始的
+ _ // 也就是说第二个才是生效的,所以当只书写structonly的时候,他会略过这个tag,那么必须跟着前面的一个标签才行,比如说 `valid="require,structonly"`,这样才会生效
+ noStructLevelTag = "nostructlevel" // 同上
+
+ omitempty = "omitempty" //read note 如果字段未设值则忽略它
+ skipValidationTag = "-" //read note 忽略字段
+ diveTag = "dive" //read note 深入到slice, array or map 里面去校验里面的字段是否正确,每一层都需要多一个【div】来标识
+ _ //read note 比如说 [][]string "gt=0,dive,dive,required" gt是校验[][]string长度,第一个div是校验[]string,第二个div是校验string
+ existsTag = "exists" //read note 校验值存在即可(除非是nil则会报错),和require的区别是说,require对默认值也会报错
+
+ //read note 数组结构的名称组成
+ arrayIndexFieldName = "%s" + leftBracket + "%d" + rightBracket
+ mapIndexFieldName = "%s" + leftBracket + "%v" + rightBracket
+
+ //read note 字段校验错误信息打印
+ fieldErrMsg = "Key: '%s' Error:Field validation for '%s' failed on the '%s' tag"
+ //read note 报错信息(非字段校验错误)
+ invalidValidation = "Invalid validation tag on field %s"
+ undefinedValidation = "Undefined validation function on field %s"
+ validatorNotInitialized = "Validator instance not initialized"
+ fieldNameRequired = "Field Name Required"
+ tagRequired = "Tag Required"
+)
+
+var (
+ timeType = reflect.TypeOf(time.Time{})
+ timePtrType = reflect.TypeOf(&time.Time{})
+ defaultCField = new(cField)
+)
+
+// StructLevel contains all of the information and helper methods
+// for reporting errors during struct level validation
+type StructLevel struct {
+ TopStruct reflect.Value
+ CurrentStruct reflect.Value
+ errPrefix string
+ nsPrefix string
+ errs ValidationErrors
+ v *Validate
+}
+
+// ReportValidationErrors accepts the key relative to the top level struct and validatin errors.
+// Example: had a triple nested struct User, ContactInfo, Country and ran errs := validate.Struct(country)
+// from within a User struct level validation would call this method like so:
+// ReportValidationErrors("ContactInfo.", errs)
+// NOTE: relativeKey can contain both the Field Relative and Custom name relative paths
+// i.e. ReportValidationErrors("ContactInfo.|cInfo", errs) where cInfo represents say the JSON name of
+// the relative path; this will be split into 2 variables in the next valiator version.
+func (sl *StructLevel) ReportValidationErrors(relativeKey string, errs ValidationErrors) {
+ for _, e := range errs {
+
+ idx := strings.Index(relativeKey, "|")
+ var rel string
+ var cRel string
+
+ if idx != -1 {
+ rel = relativeKey[:idx]
+ cRel = relativeKey[idx+1:]
+ } else {
+ rel = relativeKey
+ }
+
+ key := sl.errPrefix + rel + e.Field
+
+ e.FieldNamespace = key
+ e.NameNamespace = sl.nsPrefix + cRel + e.Name
+
+ sl.errs[key] = e
+ }
+}
+
+// ReportError reports an error just by passing the field and tag information
+// NOTE: tag can be an existing validation tag or just something you make up
+// and precess on the flip side it's up to you.
+func (sl *StructLevel) ReportError(field reflect.Value, fieldName string, customName string, tag string) {
+
+ field, kind := sl.v.ExtractType(field)
+
+ if fieldName == blank {
+ panic(fieldNameRequired)
+ }
+
+ if customName == blank {
+ customName = fieldName
+ }
+
+ if tag == blank {
+ panic(tagRequired)
+ }
+
+ ns := sl.errPrefix + fieldName
+
+ switch kind {
+ case reflect.Invalid:
+ sl.errs[ns] = &FieldError{
+ FieldNamespace: ns,
+ NameNamespace: sl.nsPrefix + customName,
+ Name: customName,
+ Field: fieldName,
+ Tag: tag,
+ ActualTag: tag,
+ Param: blank,
+ Kind: kind,
+ }
+ default:
+ sl.errs[ns] = &FieldError{
+ FieldNamespace: ns,
+ NameNamespace: sl.nsPrefix + customName,
+ Name: customName,
+ Field: fieldName,
+ Tag: tag,
+ ActualTag: tag,
+ Param: blank,
+ Value: field.Interface(),
+ Kind: kind,
+ Type: field.Type(),
+ }
+ }
+}
+
+// Validate contains the validator settings passed in using the Config struct
+type Validate struct {
+ tagName string //校验起作用的tag名
+ fieldNameTag string //
+ validationFuncs map[string]Func //规则类型的校验 【tag标签】-> 校验规则
+ structLevelFuncs map[reflect.Type]StructLevelFunc //规则结构体的校验 【结构体类型】-> 校验规则
+ customTypeFuncs map[reflect.Type]CustomTypeFunc //类型校验器 【数据类型】-> 校验规则
+ aliasValidators map[string]string //别名校验器 【别名匹配规则组合】-> 校验规则
+ hasCustomFuncs bool //是否存在类型校验器
+ hasAliasValidators bool //是否有别名校验器
+ hasStructLevelFuncs bool //是否有结构体校验器
+ tagCache *tagCache //tag对应的【校验规则方法】的缓存
+ structCache *structCache //结构体对应的【校验规则方法】的缓存
+ errsPool *sync.Pool //校验错误奖池
+}
+
+func (v *Validate) initCheck() {
+ if v == nil {
+ panic(validatorNotInitialized)
+ }
+}
+
+// Config contains the options that a Validator instance will use.
+// It is passed to the New() function
+type Config struct {
+ TagName string
+ FieldNameTag string
+}
+
+// CustomTypeFunc allows for overriding or adding custom field type handler functions
+// field = field value of the type to return a value to be validated
+// example Valuer from sql drive see https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29
+type CustomTypeFunc func(field reflect.Value) interface{}
+
+// Func accepts all values needed for file and cross field validation
+// v = validator instance, needed but some built in functions for it's custom types
+// topStruct = top level struct when validating by struct otherwise nil
+// currentStruct = current level struct when validating by struct otherwise optional comparison value
+// field = field value for validation
+// param = parameter used in validation i.e. gt=0 param would be 0
+type Func func(v *Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldtype reflect.Type, fieldKind reflect.Kind, param string) bool
+
+// StructLevelFunc accepts all values needed for struct level validation
+type StructLevelFunc func(v *Validate, structLevel *StructLevel)
+
+// ValidationErrors is a type of map[string]*FieldError
+// it exists to allow for multiple errors to be passed from this library
+// and yet still subscribe to the error interface
+type ValidationErrors map[string]*FieldError
+
+// Error is intended for use in development + debugging and not intended to be a production error message.
+// It allows ValidationErrors to subscribe to the Error interface.
+// All information to create an error message specific to your application is contained within
+// the FieldError found within the ValidationErrors map
+func (ve ValidationErrors) Error() string {
+
+ buff := bytes.NewBufferString(blank)
+
+ for key, err := range ve {
+ buff.WriteString(fmt.Sprintf(fieldErrMsg, key, err.Field, err.Tag))
+ buff.WriteString("\n")
+ }
+
+ return strings.TrimSpace(buff.String())
+}
+
+// FieldError contains a single field's validation error along
+// with other properties that may be needed for error message creation
+type FieldError struct {
+ FieldNamespace string
+ NameNamespace string
+ Field string
+ Name string
+ Tag string
+ ActualTag string
+ Kind reflect.Kind
+ Type reflect.Type
+ Param string
+ Value interface{}
+}
+
+// New creates a new Validate instance for use.
+func New(config *Config) *Validate {
+
+ //read note tag校验器缓存,初始化
+ tc := new(tagCache)
+ tc.m.Store(make(map[string]*cTag))
+
+ //read note 结构体缓存,初始化一个Map,防止后面添加的时候报错
+ sc := new(structCache)
+ sc.m.Store(make(map[reflect.Type]*cStruct))
+
+ v := &Validate{
+ tagName: config.TagName,
+ fieldNameTag: config.FieldNameTag,
+ tagCache: tc,
+ structCache: sc,
+ //read note 自定义一个错误池
+ errsPool: &sync.Pool{New: func() interface{} {
+ return ValidationErrors{}
+ }}}
+
+ //read note 设置别名规则类(一组) 可参考: baked_in.go/bakedInAliasValidators
+ if len(v.aliasValidators) == 0 {
+ // must copy alias validators for separate validations to be used in each validator instance
+ v.aliasValidators = map[string]string{}
+ for k, val := range bakedInAliasValidators {
+ //read note 默认别名校验器注册
+ v.RegisterAliasValidation(k, val)
+ }
+ }
+
+ //read note 设置默认的校验方法.可参考: baked_in.go/bakedInValidators
+ if len(v.validationFuncs) == 0 {
+ // must copy validators for separate validations to be used in each instance
+ v.validationFuncs = map[string]Func{}
+ for k, val := range bakedInValidators {
+ //read note 默认tag校验器注册
+ v.RegisterValidation(k, val)
+ }
+ }
+
+ return v
+}
+
+// RegisterStructValidation registers a StructLevelFunc against a number of types
+// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
+func (v *Validate) RegisterStructValidation(fn StructLevelFunc, types ...interface{}) {
+ v.initCheck()
+
+ if v.structLevelFuncs == nil {
+ v.structLevelFuncs = map[reflect.Type]StructLevelFunc{}
+ }
+
+ for _, t := range types {
+ v.structLevelFuncs[reflect.TypeOf(t)] = fn
+ fmt.Println(reflect.TypeOf(t))
+ }
+
+ v.hasStructLevelFuncs = true
+}
+
+// RegisterValidation adds a validation Func to a Validate's map of validators denoted by the key
+// NOTE: if the key already exists, the previous validation function will be replaced.
+// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
+func (v *Validate) RegisterValidation(key string, fn Func) error {
+ v.initCheck()
+
+ if key == blank {
+ return errors.New("Function Key cannot be empty")
+ }
+
+ if fn == nil {
+ return errors.New("Function cannot be empty")
+ }
+
+ _, ok := restrictedTags[key]
+
+ if ok || strings.ContainsAny(key, restrictedTagChars) {
+ panic(fmt.Sprintf(restrictedTagErr, key))
+ }
+
+ v.validationFuncs[key] = fn
+
+ return nil
+}
+
+// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types
+// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
+//read note 注册类型的校验器,应该在校验之前就注册完成,因为该注册方法不是线程安全的.
+func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ...interface{}) {
+ v.initCheck()
+
+ if v.customTypeFuncs == nil {
+ v.customTypeFuncs = map[reflect.Type]CustomTypeFunc{}
+ }
+
+ for _, t := range types {
+ v.customTypeFuncs[reflect.TypeOf(t)] = fn
+ }
+
+ v.hasCustomFuncs = true
+}
+
+// RegisterAliasValidation registers a mapping of a single validationstag that
+// defines a common or complex set of validation(s) to simplify adding validation
+// to structs. NOTE: when returning an error the tag returned in FieldError will be
+// the alias tag unless the dive tag is part of the alias; everything after the
+// dive tag is not reported as the alias tag. Also the ActualTag in the before case
+// will be the actual tag within the alias that failed.
+// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation
+func (v *Validate) RegisterAliasValidation(alias, tags string) {
+ v.initCheck()
+
+ _, ok := restrictedTags[alias]
+
+ if ok || strings.ContainsAny(alias, restrictedTagChars) {
+ panic(fmt.Sprintf(restrictedAliasErr, alias))
+ }
+
+ v.aliasValidators[alias] = tags
+ v.hasAliasValidators = true
+}
+
+// Field validates a single field using tag style validation and returns nil or ValidationErrors as type error.
+// You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors.
+// NOTE: it returns ValidationErrors instead of a single FieldError because this can also
+// validate Array, Slice and maps fields which may contain more than one error
+//read note
+func (v *Validate) Field(field interface{}, tag string) error {
+ v.initCheck()
+
+ if len(tag) == 0 || tag == skipValidationTag {
+ return nil
+ }
+
+ errs := v.errsPool.Get().(ValidationErrors)
+ fieldVal := reflect.ValueOf(field)
+
+ //read note 从tag缓存中获取 tag标签对应的校验方法
+ ctag, ok := v.tagCache.Get(tag)
+ if !ok {
+ //read note 加锁
+ v.tagCache.lock.Lock()
+ defer v.tagCache.lock.Unlock()
+
+ // could have been multiple trying to access, but once first is done this ensures tag
+ // isn't parsed again.
+ //read note 加锁之后在这边再获取一次,因为在上一次判断到加锁的过程中,可能有函数已经把对应方法加载进来了
+ ctag, ok = v.tagCache.Get(tag)
+ if !ok {
+ //read note
+ ctag, _ = v.parseFieldTagsRecursive(tag, blank, blank, false)
+ //read note 进行标签设值
+ v.tagCache.Set(tag, ctag)
+ }
+ }
+
+ v.traverseField(fieldVal, fieldVal, fieldVal, blank, blank, errs, false, false, nil, nil, defaultCField, ctag)
+
+ //read note 判断校验错误是否存在
+ if len(errs) == 0 {
+ v.errsPool.Put(errs)
+ return nil
+ }
+
+ return errs
+}
+
+// FieldWithValue validates a single field, against another fields value using tag style validation and returns nil or ValidationErrors.
+// You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors.
+// NOTE: it returns ValidationErrors instead of a single FieldError because this can also
+// validate Array, Slice and maps fields which may contain more than one error
+func (v *Validate) FieldWithValue(val interface{}, field interface{}, tag string) error {
+ v.initCheck()
+
+ if len(tag) == 0 || tag == skipValidationTag {
+ return nil
+ }
+
+ errs := v.errsPool.Get().(ValidationErrors)
+ topVal := reflect.ValueOf(val)
+
+ ctag, ok := v.tagCache.Get(tag)
+ if !ok {
+ v.tagCache.lock.Lock()
+ defer v.tagCache.lock.Unlock()
+
+ // could have been multiple trying to access, but once first is done this ensures tag
+ // isn't parsed again.
+ ctag, ok = v.tagCache.Get(tag)
+ if !ok {
+ ctag, _ = v.parseFieldTagsRecursive(tag, blank, blank, false)
+ v.tagCache.Set(tag, ctag)
+ }
+ }
+
+ v.traverseField(topVal, topVal, reflect.ValueOf(field), blank, blank, errs, false, false, nil, nil, defaultCField, ctag)
+
+ if len(errs) == 0 {
+ v.errsPool.Put(errs)
+ return nil
+ }
+
+ return errs
+}
+
+// StructPartial validates the fields passed in only, ignoring all others.
+// Fields may be provided in a namespaced fashion relative to the struct provided
+// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name and returns nil or ValidationErrors as error
+// You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors.
+func (v *Validate) StructPartial(current interface{}, fields ...string) error {
+ v.initCheck()
+
+ sv, _ := v.ExtractType(reflect.ValueOf(current))
+ name := sv.Type().Name()
+ m := map[string]struct{}{}
+
+ if fields != nil {
+ for _, k := range fields {
+
+ flds := strings.Split(k, namespaceSeparator)
+ if len(flds) > 0 {
+
+ key := name + namespaceSeparator
+ for _, s := range flds {
+
+ idx := strings.Index(s, leftBracket)
+
+ if idx != -1 {
+ for idx != -1 {
+ key += s[:idx]
+ m[key] = struct{}{}
+
+ idx2 := strings.Index(s, rightBracket)
+ idx2++
+ key += s[idx:idx2]
+ m[key] = struct{}{}
+ s = s[idx2:]
+ idx = strings.Index(s, leftBracket)
+ }
+ } else {
+
+ key += s
+ m[key] = struct{}{}
+ }
+
+ key += namespaceSeparator
+ }
+ }
+ }
+ }
+
+ errs := v.errsPool.Get().(ValidationErrors)
+
+ v.ensureValidStruct(sv, sv, sv, blank, blank, errs, true, len(m) != 0, false, m, false)
+
+ if len(errs) == 0 {
+ v.errsPool.Put(errs)
+ return nil
+ }
+
+ return errs
+}
+
+// StructExcept validates all fields except the ones passed in.
+// Fields may be provided in a namespaced fashion relative to the struct provided
+// i.e. NestedStruct.Field or NestedArrayField[0].Struct.Name and returns nil or ValidationErrors as error
+// You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors.
+func (v *Validate) StructExcept(current interface{}, fields ...string) error {
+ v.initCheck()
+
+ sv, _ := v.ExtractType(reflect.ValueOf(current))
+ name := sv.Type().Name()
+ m := map[string]struct{}{}
+
+ for _, key := range fields {
+ m[name+namespaceSeparator+key] = struct{}{}
+ }
+
+ errs := v.errsPool.Get().(ValidationErrors)
+
+ v.ensureValidStruct(sv, sv, sv, blank, blank, errs, true, len(m) != 0, true, m, false)
+
+ if len(errs) == 0 {
+ v.errsPool.Put(errs)
+ return nil
+ }
+
+ return errs
+}
+
+// Struct validates a structs exposed fields, and automatically validates nested structs, unless otherwise specified.
+// it returns nil or ValidationErrors as error.
+// You will need to assert the error if it's not nil i.e. err.(validator.ValidationErrors) to access the map of errors.
+func (v *Validate) Struct(current interface{}) error {
+ v.initCheck()
+
+ errs := v.errsPool.Get().(ValidationErrors)
+ sv := reflect.ValueOf(current)
+
+ //read note 进行结构体校验
+ v.ensureValidStruct(sv, sv, sv, blank, blank, errs, true, false, false, nil, false)
+
+ //read note 校验之后,对校验错误进行处理.
+ if len(errs) == 0 {
+ v.errsPool.Put(errs)
+ return nil
+ }
+
+ return errs
+}
+
+func (v *Validate) ensureValidStruct(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, nsPrefix string, errs ValidationErrors, useStructName bool, partial bool, exclude bool, includeExclude map[string]struct{}, isStructOnly bool) {
+
+ //read note 指针处理成结构体Value(返回其指向的实际结构体)
+ if current.Kind() == reflect.Ptr && !current.IsNil() {
+ current = current.Elem()
+ }
+
+ //read note 结构体类型校验.
+ if current.Kind() != reflect.Struct && current.Kind() != reflect.Interface {
+ panic("value passed for validation is not a struct")
+ }
+
+ //read note 校验结构体
+ v.tranverseStruct(topStruct, currentStruct, current, errPrefix, nsPrefix, errs, useStructName, partial, exclude, includeExclude, nil, nil)
+}
+
+// tranverseStruct traverses a structs fields and then passes them to be validated by traverseField
+func (v *Validate) tranverseStruct(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, nsPrefix string, errs ValidationErrors, useStructName bool, partial bool, exclude bool, includeExclude map[string]struct{}, cs *cStruct, ct *cTag) {
+
+ var ok bool
+ first := len(nsPrefix) == 0
+ typ := current.Type()
+
+ //read note 结构体校验器_缓存
+ cs, ok = v.structCache.Get(typ)
+ if !ok {
+ cs = v.extractStructCache(current, typ.Name())
+ }
+
+ if useStructName {
+ errPrefix += cs.Name + namespaceSeparator
+
+ if len(v.fieldNameTag) != 0 {
+ nsPrefix += cs.Name + namespaceSeparator
+ }
+ }
+
+ // structonly tag present don't tranverseFields
+ // but must still check and run below struct level validation
+ // if present
+ //read note 【structonly】标签会忽略掉Field的校验
+ if first || ct == nil || ct.typeof != typeStructOnly {
+
+ for _, f := range cs.fields {
+
+ if partial {
+
+ _, ok = includeExclude[errPrefix+f.Name]
+
+ if (ok && exclude) || (!ok && !exclude) {
+ continue
+ }
+ }
+
+ v.traverseField(topStruct, currentStruct, current.Field(f.Idx), errPrefix, nsPrefix, errs, partial, exclude, includeExclude, cs, f, f.cTags)
+ }
+ }
+
+ // check if any struct level validations, after all field validations already checked.
+ //read note 如果结构体层的校验存在的话,需要进行调用.(这边是规则类校验)
+ if cs.fn != nil {
+ cs.fn(v, &StructLevel{v: v, TopStruct: topStruct, CurrentStruct: current, errPrefix: errPrefix, nsPrefix: nsPrefix, errs: errs})
+ }
+}
+
+// traverseField validates any field, be it a struct or single field, ensures it's validity and passes it along to be validated via it's tag options
+func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.Value, current reflect.Value, errPrefix string, nsPrefix string, errs ValidationErrors, partial bool, exclude bool, includeExclude map[string]struct{}, cs *cStruct, cf *cField, ct *cTag) {
+
+ //read note 处理Ptr、Interface、Invalid(validator自定义)、自定义结构体类型.
+ // 返回参数为:值 、 数据源类型、nullable(用来校验 【结构体】的【omiEmpty】标签...)
+ current, kind, nullable := v.extractTypeInternal(current, false)
+ var typ reflect.Type
+
+ switch kind {
+ //read note 处理地址、Interface、Invalid是直接往校验错误池中添加一个Field错误?
+ case reflect.Ptr, reflect.Interface, reflect.Invalid:
+
+ if ct == nil {
+ return
+ }
+
+ if ct.typeof == typeOmitEmpty {
+ return
+ }
+
+ if ct.hasTag {
+
+ ns := errPrefix + cf.Name
+
+ //read note 如果是Invalid,需要往校验错误池中添加一个Field错误
+ if kind == reflect.Invalid {
+ errs[ns] = &FieldError{
+ FieldNamespace: ns,
+ NameNamespace: nsPrefix + cf.AltName,
+ Name: cf.AltName,
+ Field: cf.Name,
+ Tag: ct.aliasTag,
+ ActualTag: ct.tag,
+ Param: ct.param,
+ Kind: kind,
+ }
+ return
+ }
+
+ errs[ns] = &FieldError{
+ FieldNamespace: ns,
+ NameNamespace: nsPrefix + cf.AltName,
+ Name: cf.AltName,
+ Field: cf.Name,
+ Tag: ct.aliasTag,
+ ActualTag: ct.tag,
+ Param: ct.param,
+ Value: current.Interface(),
+ Kind: kind,
+ Type: current.Type(),
+ }
+
+ return
+ }
+
+ case reflect.Struct:
+ typ = current.Type()
+
+ if typ != timeType {
+
+ //read note 对于结构体,这边有一个比较特殊的处理就是cTag是从第二个位置开始,也就是之前一直尝试structonly不成功,就是需要在structonly前面加一个tag才行。
+ // 前一个对于struct应该是不生效才对,第二个才会对struct生效
+ if ct != nil {
+ ct = ct.next
+ }
+
+ if ct != nil && ct.typeof == typeNoStructLevel {
+ return
+ }
+
+ //read note 如果上面的cTag没有生效/没有tagType为【typeNoStructLevel】的标签.就直接进入这个结构体
+ v.tranverseStruct(topStruct, current, current, errPrefix+cf.Name+namespaceSeparator, nsPrefix+cf.AltName+namespaceSeparator, errs, false, partial, exclude, includeExclude, cs, ct)
+ return
+ }
+ }
+
+ if !ct.hasTag {
+ return
+ }
+
+ typ = current.Type()
+
+ //read note 进行字段Field的校验,这边的话是一个for的循环,在不同的标签中去找到对应的处理方式
+OUTER:
+ for {
+ if ct == nil {
+ return
+ }
+
+ switch ct.typeof {
+
+ case typeExists:
+ ct = ct.next
+ continue
+
+ case typeOmitEmpty:
+
+ if !nullable && !HasValue(v, topStruct, currentStruct, current, typ, kind, blank) {
+ return
+ }
+
+ ct = ct.next
+ continue
+
+ case typeDive:
+
+ ct = ct.next
+
+ // traverse slice or map here
+ // or panic ;)
+ switch kind {
+ //read note 【dive】标签处理Slice 和 Array:往数组中的每一个元素进行处理
+ case reflect.Slice, reflect.Array:
+
+ for i := 0; i < current.Len(); i++ {
+ v.traverseField(topStruct, currentStruct, current.Index(i), errPrefix, nsPrefix, errs, partial, exclude, includeExclude, cs, &cField{Name: fmt.Sprintf(arrayIndexFieldName, cf.Name, i), AltName: fmt.Sprintf(arrayIndexFieldName, cf.AltName, i)}, ct)
+ }
+ //read note 【dive】标签处理 Map:往Map中的每一个元素进行处理
+ case reflect.Map:
+ for _, key := range current.MapKeys() {
+ v.traverseField(topStruct, currentStruct, current.MapIndex(key), errPrefix, nsPrefix, errs, partial, exclude, includeExclude, cs, &cField{Name: fmt.Sprintf(mapIndexFieldName, cf.Name, key.Interface()), AltName: fmt.Sprintf(mapIndexFieldName, cf.AltName, key.Interface())}, ct)
+ }
+ //read note 【div】只能标注在 Slice 、 Map 、Array 上,不然就是报错.
+ default:
+ // throw error, if not a slice or map then should not have gotten here
+ // bad dive tag
+ panic("dive error! can't dive on a non slice or map")
+ }
+
+ return
+
+ case typeOr:
+
+ //read note 【|】的处理
+ errTag := blank
+
+ for {
+
+ //read note 如果结果是true的话,因为【|】标签只要有一个成立就可以,所以可以直接排除掉其他 【|】标签了
+ if ct.fn(v, topStruct, currentStruct, current, typ, kind, ct.param) {
+
+ // drain rest of the 'or' values, then continue or leave
+ //read note 排除其他 【|】标签,直到下一个Field的非【|】标签再进入处理.
+ for {
+
+ ct = ct.next
+
+ if ct == nil {
+ return
+ }
+
+ if ct.typeof != typeOr {
+ continue OUTER
+ }
+ }
+ }
+
+ errTag += orSeparator + ct.tag
+
+ //read note 没有下一个cTag的处理器.处理一i西安错误信息,返回.
+ if ct.next == nil {
+ // if we get here, no valid 'or' value and no more tags
+
+ ns := errPrefix + cf.Name
+
+ if ct.hasAlias {
+ errs[ns] = &FieldError{
+ FieldNamespace: ns,
+ NameNamespace: nsPrefix + cf.AltName,
+ Name: cf.AltName,
+ Field: cf.Name,
+ Tag: ct.aliasTag,
+ ActualTag: ct.actualAliasTag,
+ Value: current.Interface(),
+ Type: typ,
+ Kind: kind,
+ }
+ } else {
+ errs[errPrefix+cf.Name] = &FieldError{
+ FieldNamespace: ns,
+ NameNamespace: nsPrefix + cf.AltName,
+ Name: cf.AltName,
+ Field: cf.Name,
+ Tag: errTag[1:],
+ ActualTag: errTag[1:],
+ Value: current.Interface(),
+ Type: typ,
+ Kind: kind,
+ }
+ }
+
+ return
+ }
+
+ ct = ct.next
+ }
+
+ default:
+ //read note 剩下的标签处理.类似一个循环的处理
+ if !ct.fn(v, topStruct, currentStruct, current, typ, kind, ct.param) {
+
+ ns := errPrefix + cf.Name
+
+ errs[ns] = &FieldError{
+ FieldNamespace: ns,
+ NameNamespace: nsPrefix + cf.AltName,
+ Name: cf.AltName,
+ Field: cf.Name,
+ Tag: ct.aliasTag,
+ ActualTag: ct.tag,
+ Value: current.Interface(),
+ Param: ct.param,
+ Type: typ,
+ Kind: kind,
+ }
+
+ return
+
+ }
+
+ ct = ct.next
+ }
+ }
+}
diff --git a/SourceAnalysisAndTool/validator.v8/testValidator/Data.go b/SourceAnalysisAndTool/validator.v8/testValidator/Data.go
new file mode 100644
index 0000000..57bcb23
--- /dev/null
+++ b/SourceAnalysisAndTool/validator.v8/testValidator/Data.go
@@ -0,0 +1,33 @@
+/*
+ * @Author : huangzj
+ * @Time : 2020/12/11 16:16
+ * @Description:
+ */
+
+package testValidator
+
+type Ower struct {
+ Age int `validate:"min=10"`
+}
+
+type Cat struct {
+ Age int `validate:"min=10"`
+ Ower Ower
+}
+
+type Man struct {
+ Name string `validate:"ipe"`
+}
+
+type Woman struct {
+ Name string `validate:"diy=5"`
+}
+
+type Person struct {
+ Name string
+ M map[string]int `validate:"min=10"`
+ H int `validate:"max=20"`
+ Exist bool `validate:"exists"`
+ Require bool `validate:"required"`
+ Cat Cat
+}
diff --git a/SourceAnalysisAndTool/validator.v8/testValidator/Validator_test.go b/SourceAnalysisAndTool/validator.v8/testValidator/Validator_test.go
new file mode 100644
index 0000000..d6a98bc
--- /dev/null
+++ b/SourceAnalysisAndTool/validator.v8/testValidator/Validator_test.go
@@ -0,0 +1,158 @@
+/*
+ * @Author : huangzj
+ * @Time : 2020/12/11 16:16
+ * @Description:
+ */
+
+package testValidator
+
+import (
+ "Go-Tool/SourceAnalysisAndTool/validator.v8/sourceAnalysis/gopkg.in/go-playground/validator.v8"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+ "testing"
+)
+
+func TestValidator(t *testing.T) {
+ fmt.Println("测试别名校验器")
+ testAlias()
+
+ fmt.Println()
+ fmt.Println("测试默认和自定义tag校验器")
+ testTag()
+
+ fmt.Println()
+ fmt.Println("测试字段校验器")
+ testField()
+
+ fmt.Println()
+ fmt.Println("测试结构体校验器")
+ testStruct()
+
+}
+
+func testStruct() {
+ //添加结构体校验,对结构体进行处理之后,validator的标签还是会起作用
+ config := &validator.Config{
+ TagName: "validate",
+ }
+ valid := validator.New(config)
+ valid.RegisterStructValidation(func(v *validator.Validate, structLevel *validator.StructLevel) {
+ c := structLevel.CurrentStruct.Interface().(Cat)
+ if c.Age < 100 {
+ fmt.Println("猫的岁数不能小于100")
+ }
+ }, Cat{})
+ p := Person{
+ Name: "192.168.0.1",
+ M: map[string]int{"A": 1},
+ H: 2000,
+ Exist: false,
+ Require: false,
+ Cat: Cat{
+ Age: 0,
+ Ower: Ower{},
+ },
+ }
+
+ err := valid.Struct(p)
+ fmt.Println(err)
+}
+
+func testField() {
+ //如果注册了对应的Field,则会调用自定义的方法,不会再使用validator定义的标签
+ //这边测试了结构体和基本类型,都是如上述描述的这么处理
+ config := &validator.Config{
+ TagName: "validate",
+ }
+ valid := validator.New(config)
+ valid.RegisterAliasValidation("ipe", "ip|ipv4|ipv6")
+
+ valid.RegisterCustomTypeFunc(func(field reflect.Value) interface{} {
+ d := field.Interface().(Cat)
+ if d.Age < 50 {
+ fmt.Println("狗的岁数不能小于50")
+ }
+ return field
+ }, Cat{})
+
+ p := Person{
+ Name: "192.168.0.1",
+ M: map[string]int{"A": 1},
+ H: 2000,
+ Exist: false,
+ Require: false,
+ Cat: Cat{
+ Age: 0,
+ Ower: Ower{},
+ },
+ }
+ err := valid.Struct(p)
+ fmt.Println(err)
+
+ valid.RegisterCustomTypeFunc(func(field reflect.Value) interface{} {
+ d := field.Interface().(int)
+ if d != 10 {
+ fmt.Println("测试一下")
+ }
+ return field
+ }, 1)
+
+ err1 := valid.Struct(p)
+ fmt.Println(err1)
+
+}
+
+func testTag() {
+ w := Woman{
+ Name: "my name is Woman",
+ }
+
+ w1 := Woman{
+ Name: "my name is wo-man",
+ }
+
+ config := &validator.Config{
+ TagName: "validate",
+ }
+ valid := validator.New(config)
+ _ = valid.RegisterValidation("diy", func(v *validator.Validate, topStruct reflect.Value, currentStruct reflect.Value, field reflect.Value, fieldtype reflect.Type, fieldKind reflect.Kind, param string) bool {
+ s := field.Interface().(string)
+
+ i, _ := strconv.ParseInt(param, 0, 64)
+ if int64(len(s)) < i || strings.Contains(s, "Woman") {
+ fmt.Println("校验一下")
+ return false
+ }
+ return true
+ })
+
+ err := valid.Struct(w)
+ fmt.Println(err)
+
+ err1 := valid.Struct(w1)
+ fmt.Println(err1)
+}
+
+func testAlias() {
+ m := Man{
+ Name: "192.168.0.1",
+ }
+
+ m1 := Man{
+ Name: "213123123",
+ }
+
+ config := &validator.Config{
+ TagName: "validate",
+ }
+ valid := validator.New(config)
+ valid.RegisterAliasValidation("ipe", "ip|ipv4|ipv6")
+ err := valid.Struct(m)
+ fmt.Println(err)
+
+ err1 := valid.Struct(m1)
+ fmt.Println(err1)
+}
diff --git a/go.mod b/go.mod
index 7855d5e..eed629d 100644
--- a/go.mod
+++ b/go.mod
@@ -4,16 +4,18 @@ go 1.13
require (
github.com/Bowery/prompt v0.0.0-20190916142128-fa8279994f75 // indirect
- github.com/ahmetalpbalkan/go-linq v2.0.0-rc0+incompatible
- github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/ahmetalpbalkan/go-linq v2.0.0-rc0+incompatible // indirect
+ github.com/ahmetb/go-linq v2.0.0-rc0+incompatible
github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185 // indirect
github.com/go-ini/ini v1.57.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
+ github.com/json-iterator/go v1.1.10
github.com/kardianos/govendor v1.0.9 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/stretchr/testify v1.5.1 // indirect
golang.org/x/sys v0.0.0-20200428200454-593003d681fa // indirect
golang.org/x/tools v0.0.0-20200429213335-127c98bd7927 // indirect
+ gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/yaml.v2 v2.2.8 // indirect
)
diff --git a/go.sum b/go.sum
index c4f711e..1beaffa 100644
--- a/go.sum
+++ b/go.sum
@@ -2,6 +2,8 @@ github.com/Bowery/prompt v0.0.0-20190916142128-fa8279994f75 h1:xGHheKK44eC6K0u5X
github.com/Bowery/prompt v0.0.0-20190916142128-fa8279994f75/go.mod h1:4/6eNcqZ09BZ9wLK3tZOjBA1nDj+B0728nlX5YRlSmQ=
github.com/ahmetalpbalkan/go-linq v2.0.0-rc0+incompatible h1:8q+6K5jJ2RCTD7v7VxMfuUdHyU22GZi+qMY0hpLTnVc=
github.com/ahmetalpbalkan/go-linq v2.0.0-rc0+incompatible/go.mod h1:IBvGwXyZVvXuN8KIbGCK53k+fzCKOmAdYhobMdJXOck=
+github.com/ahmetb/go-linq v2.0.0-rc0+incompatible h1:H8yA1M8T+1/pyPRUwSOyc30MFrtiP9vgJ2s+lgdaQlM=
+github.com/ahmetb/go-linq v2.0.0-rc0+incompatible/go.mod h1:PFffvbdbtw+QTB0WKRP0cNht7vnCfnGlEpak/DVg5cY=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -10,16 +12,24 @@ github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185 h1:3T8ZyTDp5QxTx3N
github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185/go.mod h1:cFRxtTwTOJkz2x3rQUNCYKWC93yP1VKjR8NUhqFxZNU=
github.com/go-ini/ini v1.57.0 h1:Qwzj3wZQW+Plax5Ntj+GYe07DfGj1OH+aL1nMTMaNow=
github.com/go-ini/ini v1.57.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
+github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/kardianos/govendor v1.0.9 h1:WOH3FcVI9eOgnIZYg96iwUwrL4eOVx+aQ66oyX2R8Yc=
github.com/kardianos/govendor v1.0.9/go.mod h1:yvmR6q9ZZ7nSF5Wvh40v0wfP+3TwwL8zYQp+itoZSVM=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -45,6 +55,8 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
+gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
diff --git a/readme.md b/readme.md
index b6c7ce3..c655803 100644
--- a/readme.md
+++ b/readme.md
@@ -66,6 +66,8 @@
2020/12/7 :添加container包使用示例和源码分析
+2020/12/14:添加validator.v8源码解析和使用示例
+
# mod vendor模式加载包
通过go mod的方式加载的github上面的包会有报红的问题,但是包本身是可以运行的,这样就是会有一个问题,如果你想要点击去看方法的内容,没办法做到
diff --git a/vendor/github.com/ahmetb/go-linq/.travis.yml b/vendor/github.com/ahmetb/go-linq/.travis.yml
index 157e59f..6587753 100644
--- a/vendor/github.com/ahmetb/go-linq/.travis.yml
+++ b/vendor/github.com/ahmetb/go-linq/.travis.yml
@@ -2,13 +2,14 @@ sudo: false
language: go
go:
+ - 1.5
- 1.7
before_install:
- go get github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover
- go get -u github.com/golang/lint/golint
-
+
script:
- go vet -x ./...
- golint ./...
diff --git a/vendor/github.com/ahmetb/go-linq/LICENSE b/vendor/github.com/ahmetb/go-linq/LICENSE
index c1ab55f..71dd824 100644
--- a/vendor/github.com/ahmetb/go-linq/LICENSE
+++ b/vendor/github.com/ahmetb/go-linq/LICENSE
@@ -1,201 +1,14 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
+Copyright 2016 Ahmet Alp Balkan
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+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
- 1. Definitions.
+ http://www.apache.org/licenses/LICENSE-2.0
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
+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.
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "{}"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright 2016 Ahmet Alp Balkan
-
- 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.
diff --git a/vendor/github.com/ahmetb/go-linq/README.md b/vendor/github.com/ahmetb/go-linq/README.md
index 4e9f12b..475464c 100644
--- a/vendor/github.com/ahmetb/go-linq/README.md
+++ b/vendor/github.com/ahmetb/go-linq/README.md
@@ -1,21 +1,16 @@
# go-linq [](https://godoc.org/github.com/ahmetalpbalkan/go-linq) [](https://travis-ci.org/ahmetalpbalkan/go-linq) [](https://coveralls.io/github/ahmetalpbalkan/go-linq?branch=master) [](https://goreportcard.com/report/github.com/ahmetalpbalkan/go-linq)
A powerful language integrated query (LINQ) library for Go.
-* Written in vanilla Go, no dependencies!
-* Complete lazy evaluation with iterator pattern
+* Written in vanilla Go!
* Safe for concurrent use
-* Supports generic functions to make your code cleaner and free of type assertions
+* Complete lazy evaluation with iterator pattern
* Supports arrays, slices, maps, strings, channels and custom collections
+(collection needs to implement `Iterable` interface and element - `Comparable`
+interface)
## Installation
$ go get github.com/ahmetalpbalkan/go-linq
-We recommend using a dependency manager (e.g. [govendor][govendor] or
-[godep][godep]) to maintain a local copy of this package in your project.
-
-[govendor]: https://github.com/kardianos/govendor
-[godep]: https://github.com/tools/godep/
-
> :warning: :warning: `go-linq` has recently introduced _breaking API changes_
> with v2.0.0. See [release notes](#release-notes) for details. v2.0.0 comes with
> a refined interface, dramatically increased performance and memory efficiency,
@@ -31,20 +26,16 @@ Usage is as easy as chaining methods like:
`From(slice)` `.Where(predicate)` `.Select(selector)` `.Union(data)`
-**Example 1: Find all owners of cars manufactured after 2015**
-
+**Example: Find all owners of cars manufactured from 2015**
```go
import . "github.com/ahmetalpbalkan/go-linq"
type Car struct {
- year int
+ id, year int
owner, model string
}
-...
-
-
-var owners []string
+owners := []string{}
From(cars).Where(func(c interface{}) bool {
return c.(Car).year >= 2015
@@ -53,21 +44,7 @@ From(cars).Where(func(c interface{}) bool {
}).ToSlice(&owners)
```
-Or, you can use generic functions, like `WhereT` and `SelectT` to simplify your code
-(at a performance penalty):
-
-```go
-var owners []string
-
-From(cars).WhereT(func(c Car) bool {
- return c.year >= 2015
-}).SelectT(func(c Car) string {
- return c.owner
-}).ToSlice(&owners)
-```
-
-**Example 2: Find the author who has written the most books**
-
+**Example: Find the author who has written the most books**
```go
import . "github.com/ahmetalpbalkan/go-linq"
@@ -94,8 +71,7 @@ author := From(books).SelectMany( // make a flat array of authors
}).First() // take the first author
```
-**Example 3: Implement a custom method that leaves only values greater than the specified threshold**
-
+**Example: Implement a custom method that leaves only values greater than the specified threshold**
```go
type MyQuery Query
@@ -120,67 +96,10 @@ func (q MyQuery) GreaterThan(threshold int) Query {
result := MyQuery(Range(1,10)).GreaterThan(5).Results()
```
-## Generic Functions
-
-Although Go doesn't implement generics, with some reflection tricks, you can use go-linq without
-typing `interface{}`s and type assertions. This will introduce a performance penalty (5x-10x slower)
-but will yield in a cleaner and more readable code.
-
-Methods with `T` suffix (such as `WhereT`) accept functions with generic types. So instead of
-
- .Select(func(v interface{}) interface{} {...})
-
-you can type:
-
- .SelectT(func(v YourType) YourOtherType {...})
-
-This will make your code free of `interface{}` and type assertions.
-
-**Example 4: "MapReduce" in a slice of string sentences to list the top 5 most used words using generic functions**
-
-```go
-var results []string
-
-From(sentences).
- // split sentences to words
- SelectManyT(func(sentence string) Query {
- return From(strings.Split(sentence, " "))
- }).
- // group the words
- GroupByT(
- func(word string) string { return word },
- func(word string) string { return word },
- ).
- // order by count
- OrderByDescendingT(func(wordGroup Group) int {
- return len(wordGroup.Group)
- }).
- // order by the word
- ThenByT(func(wordGroup Group) string {
- return wordGroup.Key.(string)
- }).
- Take(5). // take the top 5
- // project the words using the index as rank
- SelectIndexedT(func(index int, wordGroup Group) string {
- return fmt.Sprintf("Rank: #%d, Word: %s, Counts: %d", index+1, wordGroup.Key, len(wordGroup.Group))
- }).
- ToSlice(&results)
-```
-
-**More examples** can be found in the [documentation](https://godoc.org/github.com/ahmetalpbalkan/go-linq).
+**More examples** can be found in [documentation](https://godoc.org/github.com/ahmetalpbalkan/go-linq).
## Release Notes
-
~~~
-v3.0.0 (2017-01-10)
-* Breaking change: ToSlice() now overwrites existing slice starting
- from index 0 and grows/reslices it as needed.
-* Generic methods support (thanks @cleitonmarx!)
- - Accepting parametrized functions was originally proposed in #26
- - You can now avoid type assertions and interface{}s
- - Functions with generic methods are named as "MethodNameT" and
- signature for the existing LINQ methods are unchanged.
-* Added ForEach(), ForEachIndexed() and AggregateWithSeedBy().
v2.0.0 (2016-09-02)
* IMPORTANT: This release is a BREAKING CHANGE. The old version
diff --git a/vendor/github.com/ahmetb/go-linq/aggregate.go b/vendor/github.com/ahmetb/go-linq/aggregate.go
index bb1975d..a8658c5 100644
--- a/vendor/github.com/ahmetb/go-linq/aggregate.go
+++ b/vendor/github.com/ahmetb/go-linq/aggregate.go
@@ -2,15 +2,16 @@ package linq
// Aggregate applies an accumulator function over a sequence.
//
-// Aggregate method makes it simple to perform a calculation over a sequence of
-// values. This method works by calling f() one time for each element in source
-// except the first one. Each time f() is called, Aggregate passes both the
-// element from the sequence and an aggregated value (as the first argument to
-// f()). The first element of source is used as the initial aggregate value. The
-// result of f() replaces the previous aggregated value.
+// Aggregate method makes it simple to perform a calculation over a sequence of values.
+// This method works by calling f() one time for each element in source
+// except the first one. Each time f() is called, Aggregate passes both
+// the element from the sequence and an aggregated value (as the first argument to f()).
+// The first element of source is used as the initial aggregate value.
+// The result of f() replaces the previous aggregated value.
//
// Aggregate returns the final result of f().
-func (q Query) Aggregate(f func(interface{}, interface{}) interface{}) interface{} {
+func (q Query) Aggregate(
+ f func(interface{}, interface{}) interface{}) interface{} {
next := q.Iterate()
result, any := next()
@@ -25,40 +26,21 @@ func (q Query) Aggregate(f func(interface{}, interface{}) interface{}) interface
return result
}
-// AggregateT is the typed version of Aggregate.
+// AggregateWithSeed applies an accumulator function over a sequence.
+// The specified seed value is used as the initial accumulator value.
//
-// - f is of type: func(TSource, TSource) TSource
-//
-// NOTE: Aggregate has better performance than AggregateT.
-func (q Query) AggregateT(f interface{}) interface{} {
- fGenericFunc, err := newGenericFunc(
- "AggregateT", "f", f,
- simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- fFunc := func(result interface{}, current interface{}) interface{} {
- return fGenericFunc.Call(result, current)
- }
-
- return q.Aggregate(fFunc)
-}
-
-// AggregateWithSeed applies an accumulator function over a sequence. The
-// specified seed value is used as the initial accumulator value.
-//
-// Aggregate method makes it simple to perform a calculation over a sequence of
-// values. This method works by calling f() one time for each element in source
-// except the first one. Each time f() is called, Aggregate passes both the
-// element from the sequence and an aggregated value (as the first argument to
-// f()). The value of the seed parameter is used as the initial aggregate value.
+// Aggregate method makes it simple to perform a calculation over a sequence of values.
+// This method works by calling f() one time for each element in source
+// except the first one. Each time f() is called, Aggregate passes both
+// the element from the sequence and an aggregated value (as the first argument to f()).
+// The value of the seed parameter is used as the initial aggregate value.
// The result of f() replaces the previous aggregated value.
//
// Aggregate returns the final result of f().
-func (q Query) AggregateWithSeed(seed interface{},
- f func(interface{}, interface{}) interface{}) interface{} {
+func (q Query) AggregateWithSeed(
+ seed interface{},
+ f func(interface{}, interface{}) interface{},
+) interface{} {
next := q.Iterate()
result := seed
@@ -69,90 +51,3 @@ func (q Query) AggregateWithSeed(seed interface{},
return result
}
-
-// AggregateWithSeedT is the typed version of AggregateWithSeed.
-//
-// - f is of type "func(TAccumulate, TSource) TAccumulate"
-//
-// NOTE: AggregateWithSeed has better performance than
-// AggregateWithSeedT.
-func (q Query) AggregateWithSeedT(seed interface{},
- f interface{}) interface{} {
- fGenericFunc, err := newGenericFunc(
- "AggregateWithSeed", "f", f,
- simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- fFunc := func(result interface{}, current interface{}) interface{} {
- return fGenericFunc.Call(result, current)
- }
-
- return q.AggregateWithSeed(seed, fFunc)
-}
-
-// AggregateWithSeedBy applies an accumulator function over a sequence. The
-// specified seed value is used as the initial accumulator value, and the
-// specified function is used to select the result value.
-//
-// Aggregate method makes it simple to perform a calculation over a sequence of
-// values. This method works by calling f() one time for each element in source.
-// Each time func is called, Aggregate passes both the element from the sequence
-// and an aggregated value (as the first argument to func). The value of the
-// seed parameter is used as the initial aggregate value. The result of func
-// replaces the previous aggregated value.
-//
-// The final result of func is passed to resultSelector to obtain the final
-// result of Aggregate.
-func (q Query) AggregateWithSeedBy(seed interface{},
- f func(interface{}, interface{}) interface{},
- resultSelector func(interface{}) interface{}) interface{} {
-
- next := q.Iterate()
- result := seed
-
- for current, ok := next(); ok; current, ok = next() {
- result = f(result, current)
- }
-
- return resultSelector(result)
-}
-
-// AggregateWithSeedByT is the typed version of AggregateWithSeedBy.
-//
-// - f is of type "func(TAccumulate, TSource) TAccumulate"
-// - resultSelectorFn is of type "func(TAccumulate) TResult"
-//
-// NOTE: AggregateWithSeedBy has better performance than
-// AggregateWithSeedByT.
-func (q Query) AggregateWithSeedByT(seed interface{},
- f interface{},
- resultSelectorFn interface{}) interface{} {
- fGenericFunc, err := newGenericFunc(
- "AggregateWithSeedByT", "f", f,
- simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- fFunc := func(result interface{}, current interface{}) interface{} {
- return fGenericFunc.Call(result, current)
- }
-
- resultSelectorGenericFunc, err := newGenericFunc(
- "AggregateWithSeedByT", "resultSelectorFn", resultSelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- resultSelectorFunc := func(result interface{}) interface{} {
- return resultSelectorGenericFunc.Call(result)
- }
-
- return q.AggregateWithSeedBy(seed, fFunc, resultSelectorFunc)
-}
diff --git a/vendor/github.com/ahmetb/go-linq/compare.go b/vendor/github.com/ahmetb/go-linq/compare.go
index 3e0ffbf..c78e4aa 100644
--- a/vendor/github.com/ahmetb/go-linq/compare.go
+++ b/vendor/github.com/ahmetb/go-linq/compare.go
@@ -2,21 +2,21 @@ package linq
type comparer func(interface{}, interface{}) int
-// Comparable is an interface that has to be implemented by a custom collection
-// elememts in order to work with linq.
+// Comparable is an interface that has to be implemented by a
+// custom collection elememts in order to work with linq.
//
// Example:
-// func (f foo) CompareTo(c Comparable) int {
-// a, b := f.f1, c.(foo).f1
+// func (f foo) CompareTo(c Comparable) int {
+// a, b := f.f1, c.(foo).f1
//
-// if a < b {
-// return -1
-// } else if a > b {
-// return 1
-// }
+// if a < b {
+// return -1
+// } else if a > b {
+// return 1
+// }
//
-// return 0
-// }
+// return 0
+// }
type Comparable interface {
CompareTo(Comparable) int
}
diff --git a/vendor/github.com/ahmetb/go-linq/concat.go b/vendor/github.com/ahmetb/go-linq/concat.go
index 3101c56..6210126 100644
--- a/vendor/github.com/ahmetb/go-linq/concat.go
+++ b/vendor/github.com/ahmetb/go-linq/concat.go
@@ -1,7 +1,7 @@
package linq
-// Append inserts an item to the end of a collection, so it becomes the last
-// item.
+// Append inserts an item to the end of a collection,
+// so it becomes the last item.
func (q Query) Append(item interface{}) Query {
return Query{
Iterate: func() Iterator {
@@ -28,8 +28,8 @@ func (q Query) Append(item interface{}) Query {
// Concat concatenates two collections.
//
// The Concat method differs from the Union method because the Concat method
-// returns all the original elements in the input sequences. The Union method
-// returns only unique elements.
+// returns all the original elements in the input sequences.
+// The Union method returns only unique elements.
func (q Query) Concat(q2 Query) Query {
return Query{
Iterate: func() Iterator {
@@ -53,8 +53,8 @@ func (q Query) Concat(q2 Query) Query {
}
}
-// Prepend inserts an item to the beginning of a collection, so it becomes the
-// first item.
+// Prepend inserts an item to the beginning of a collection,
+// so it becomes the first item.
func (q Query) Prepend(item interface{}) Query {
return Query{
Iterate: func() Iterator {
diff --git a/vendor/github.com/ahmetb/go-linq/distinct.go b/vendor/github.com/ahmetb/go-linq/distinct.go
index aaef37a..7a32c31 100644
--- a/vendor/github.com/ahmetb/go-linq/distinct.go
+++ b/vendor/github.com/ahmetb/go-linq/distinct.go
@@ -1,7 +1,7 @@
package linq
-// Distinct method returns distinct elements from a collection. The result is an
-// unordered collection that contains no duplicate values.
+// Distinct method returns distinct elements from a collection.
+// The result is an unordered collection that contains no duplicate values.
func (q Query) Distinct() Query {
return Query{
Iterate: func() Iterator {
@@ -22,11 +22,11 @@ func (q Query) Distinct() Query {
}
}
-// Distinct method returns distinct elements from a collection. The result is an
-// ordered collection that contains no duplicate values.
+// Distinct method returns distinct elements from a collection.
+// The result is an ordered collection that contains no duplicate values.
//
// NOTE: Distinct method on OrderedQuery type has better performance than
-// Distinct method on Query type.
+// Distinct method on Query type
func (oq OrderedQuery) Distinct() OrderedQuery {
return OrderedQuery{
orders: oq.orders,
@@ -73,26 +73,3 @@ func (q Query) DistinctBy(selector func(interface{}) interface{}) Query {
},
}
}
-
-// DistinctByT is the typed version of DistinctBy.
-//
-// - selectorFn is of type "func(TSource) TSource".
-//
-// NOTE: DistinctBy has better performance than DistinctByT.
-func (q Query) DistinctByT(selectorFn interface{}) Query {
- selectorFunc, ok := selectorFn.(func(interface{}) interface{})
- if !ok {
- selectorGenericFunc, err := newGenericFunc(
- "DistinctByT", "selectorFn", selectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- selectorFunc = func(item interface{}) interface{} {
- return selectorGenericFunc.Call(item)
- }
- }
- return q.DistinctBy(selectorFunc)
-}
diff --git a/vendor/github.com/ahmetb/go-linq/doc.go b/vendor/github.com/ahmetb/go-linq/doc.go
index c89c4fe..8231f70 100644
--- a/vendor/github.com/ahmetb/go-linq/doc.go
+++ b/vendor/github.com/ahmetb/go-linq/doc.go
@@ -1,6 +1,5 @@
-// Package linq provides methods for querying and manipulating slices, arrays,
-// maps, strings, channels and collections.
+// Package linq provides methods for querying and manipulating
+// slices, arrays, maps, strings, channels and collections.
//
-// Authors: Alexander Kalankhodzhaev (kalan), Ahmet Alp Balkan, Cleiton Marques
-// Souza.
+// Authors: Alexander Kalankhodzhaev (kalan), Ahmet Alp Balkan
package linq
diff --git a/vendor/github.com/ahmetb/go-linq/except.go b/vendor/github.com/ahmetb/go-linq/except.go
index d146992..c34a6b4 100644
--- a/vendor/github.com/ahmetb/go-linq/except.go
+++ b/vendor/github.com/ahmetb/go-linq/except.go
@@ -1,7 +1,8 @@
package linq
-// Except produces the set difference of two sequences. The set difference is
-// the members of the first sequence that don't appear in the second sequence.
+// Except produces the set difference of two sequences.
+// The set difference is the members of the first sequence
+// that don't appear in the second sequence.
func (q Query) Except(q2 Query) Query {
return Query{
Iterate: func() Iterator {
@@ -26,11 +27,12 @@ func (q Query) Except(q2 Query) Query {
}
}
-// ExceptBy invokes a transform function on each element of a collection and
-// produces the set difference of two sequences. The set difference is the
-// members of the first sequence that don't appear in the second sequence.
-func (q Query) ExceptBy(q2 Query,
- selector func(interface{}) interface{}) Query {
+// ExceptBy invokes a transform function on each element of a collection
+// and produces the set difference of two sequences.
+// The set difference is the members of the first sequence
+// that don't appear in the second sequence.
+func (q Query) ExceptBy(
+ q2 Query, selector func(interface{}) interface{}) Query {
return Query{
Iterate: func() Iterator {
next := q.Iterate()
@@ -55,25 +57,3 @@ func (q Query) ExceptBy(q2 Query,
},
}
}
-
-// ExceptByT is the typed version of ExceptBy.
-//
-// - selectorFn is of type "func(TSource) TSource"
-//
-// NOTE: ExceptBy has better performance than ExceptByT.
-func (q Query) ExceptByT(q2 Query,
- selectorFn interface{}) Query {
- selectorGenericFunc, err := newGenericFunc(
- "ExceptByT", "selectorFn", selectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- selectorFunc := func(item interface{}) interface{} {
- return selectorGenericFunc.Call(item)
- }
-
- return q.ExceptBy(q2, selectorFunc)
-}
diff --git a/vendor/github.com/ahmetb/go-linq/from.go b/vendor/github.com/ahmetb/go-linq/from.go
index 21ee9f4..56ab451 100644
--- a/vendor/github.com/ahmetb/go-linq/from.go
+++ b/vendor/github.com/ahmetb/go-linq/from.go
@@ -5,30 +5,30 @@ import "reflect"
// Iterator is an alias for function to iterate over data.
type Iterator func() (item interface{}, ok bool)
-// Query is the type returned from query functions. It can be iterated manually
-// as shown in the example.
+// Query is the type returned from query functions.
+// It can be iterated manually as shown in the example.
type Query struct {
Iterate func() Iterator
}
-// KeyValue is a type that is used to iterate over a map (if query is created
-// from a map). This type is also used by ToMap() method to output result of a
-// query into a map.
+// KeyValue is a type that is used to iterate over a map
+// (if query is created from a map). This type is also used by
+// ToMap() method to output result of a query into a map.
type KeyValue struct {
Key interface{}
Value interface{}
}
-// Iterable is an interface that has to be implemented by a custom collection in
-// order to work with linq.
+// Iterable is an interface that has to be implemented by a
+// custom collection in order to work with linq.
type Iterable interface {
Iterate() Iterator
}
-// From initializes a linq query with passed slice, array or map as the source.
-// String, channel or struct implementing Iterable interface can be used as an
-// input. In this case From delegates it to FromString, FromChannel and
-// FromIterable internally.
+// From initializes a linq query with passed slice, array or map
+// as the source. String, channel or struct implementing Iterable
+// interface can be used as an input. In this case From delegates it
+// to FromString, FromChannel and FromIterable internally.
func From(source interface{}) Query {
src := reflect.ValueOf(source)
@@ -84,8 +84,8 @@ func From(source interface{}) Query {
}
}
-// FromChannel initializes a linq query with passed channel, linq iterates over
-// channel until it is closed.
+// FromChannel initializes a linq query with passed channel,
+// linq iterates over channel until it is closed.
func FromChannel(source <-chan interface{}) Query {
return Query{
Iterate: func() Iterator {
@@ -97,8 +97,8 @@ func FromChannel(source <-chan interface{}) Query {
}
}
-// FromString initializes a linq query with passed string, linq iterates over
-// runes of string.
+// FromString initializes a linq query with passed string,
+// linq iterates over runes of string.
func FromString(source string) Query {
runes := []rune(source)
len := len(runes)
@@ -120,8 +120,8 @@ func FromString(source string) Query {
}
}
-// FromIterable initializes a linq query with custom collection passed. This
-// collection has to implement Iterable interface, linq iterates over items,
+// FromIterable initializes a linq query with custom collection passed.
+// This collection has to implement Iterable interface, linq iterates over items,
// that has to implement Comparable interface or be basic types.
func FromIterable(source Iterable) Query {
return Query{
diff --git a/vendor/github.com/ahmetb/go-linq/genericfunc.go b/vendor/github.com/ahmetb/go-linq/genericfunc.go
deleted file mode 100644
index 77cba2d..0000000
--- a/vendor/github.com/ahmetb/go-linq/genericfunc.go
+++ /dev/null
@@ -1,138 +0,0 @@
-package linq
-
-import (
- "fmt"
- "reflect"
- "strings"
-)
-
-// genericType represents a any reflect.Type.
-type genericType int
-
-var genericTp = reflect.TypeOf(new(genericType)).Elem()
-
-// functionCache keeps genericFunc reflection objects in cache.
-type functionCache struct {
- MethodName string
- ParamName string
- FnValue reflect.Value
- FnType reflect.Type
- TypesIn []reflect.Type
- TypesOut []reflect.Type
-}
-
-// genericFunc is a type used to validate and call dynamic functions.
-type genericFunc struct {
- Cache *functionCache
-}
-
-// Call calls a dynamic function.
-func (g *genericFunc) Call(params ...interface{}) interface{} {
- paramsIn := make([]reflect.Value, len(params))
- for i, param := range params {
- paramsIn[i] = reflect.ValueOf(param)
- }
- paramsOut := g.Cache.FnValue.Call(paramsIn)
- if len(paramsOut) >= 1 {
- return paramsOut[0].Interface()
- }
- return nil
-}
-
-// newGenericFunc instantiates a new genericFunc pointer
-func newGenericFunc(methodName, paramName string, fn interface{}, validateFunc func(*functionCache) error) (*genericFunc, error) {
- cache := &functionCache{}
- cache.FnValue = reflect.ValueOf(fn)
-
- if cache.FnValue.Kind() != reflect.Func {
- return nil, fmt.Errorf("%s: parameter [%s] is not a function type. It is a '%s'", methodName, paramName, cache.FnValue.Type())
- }
- cache.MethodName = methodName
- cache.ParamName = paramName
- cache.FnType = cache.FnValue.Type()
- numTypesIn := cache.FnType.NumIn()
- cache.TypesIn = make([]reflect.Type, numTypesIn)
- for i := 0; i < numTypesIn; i++ {
- cache.TypesIn[i] = cache.FnType.In(i)
- }
-
- numTypesOut := cache.FnType.NumOut()
- cache.TypesOut = make([]reflect.Type, numTypesOut)
- for i := 0; i < numTypesOut; i++ {
- cache.TypesOut[i] = cache.FnType.Out(i)
- }
- if err := validateFunc(cache); err != nil {
- return nil, err
- }
-
- return &genericFunc{Cache: cache}, nil
-}
-
-// simpleParamValidator creates a function to validate genericFunc based in the
-// In and Out function parameters.
-func simpleParamValidator(In []reflect.Type, Out []reflect.Type) func(cache *functionCache) error {
- return func(cache *functionCache) error {
- var isValid = func() bool {
- if In != nil {
- if len(In) != len(cache.TypesIn) {
- return false
- }
- for i, paramIn := range In {
- if paramIn != genericTp && paramIn != cache.TypesIn[i] {
- return false
- }
- }
- }
- if Out != nil {
- if len(Out) != len(cache.TypesOut) {
- return false
- }
- for i, paramOut := range Out {
- if paramOut != genericTp && paramOut != cache.TypesOut[i] {
- return false
- }
- }
- }
- return true
- }
-
- if !isValid() {
- return fmt.Errorf("%s: parameter [%s] has a invalid function signature. Expected: '%s', actual: '%s'", cache.MethodName, cache.ParamName, formatFnSignature(In, Out), formatFnSignature(cache.TypesIn, cache.TypesOut))
- }
- return nil
- }
-}
-
-// newElemTypeSlice creates a slice of items elem types.
-func newElemTypeSlice(items ...interface{}) []reflect.Type {
- typeList := make([]reflect.Type, len(items))
- for i, item := range items {
- typeItem := reflect.TypeOf(item)
- if typeItem.Kind() == reflect.Ptr {
- typeList[i] = typeItem.Elem()
- }
- }
- return typeList
-}
-
-// formatFnSignature formats the func signature based in the parameters types.
-func formatFnSignature(In []reflect.Type, Out []reflect.Type) string {
- paramInNames := make([]string, len(In))
- for i, typeIn := range In {
- if typeIn == genericTp {
- paramInNames[i] = "T"
- } else {
- paramInNames[i] = typeIn.String()
- }
-
- }
- paramOutNames := make([]string, len(Out))
- for i, typeOut := range Out {
- if typeOut == genericTp {
- paramOutNames[i] = "T"
- } else {
- paramOutNames[i] = typeOut.String()
- }
- }
- return fmt.Sprintf("func(%s)%s", strings.Join(paramInNames, ","), strings.Join(paramOutNames, ","))
-}
diff --git a/vendor/github.com/ahmetb/go-linq/groupby.go b/vendor/github.com/ahmetb/go-linq/groupby.go
index face510..2affbf8 100644
--- a/vendor/github.com/ahmetb/go-linq/groupby.go
+++ b/vendor/github.com/ahmetb/go-linq/groupby.go
@@ -6,11 +6,14 @@ type Group struct {
Group []interface{}
}
-// GroupBy method groups the elements of a collection according to a specified
-// key selector function and projects the elements for each group by using a
-// specified function.
-func (q Query) GroupBy(keySelector func(interface{}) interface{},
- elementSelector func(interface{}) interface{}) Query {
+// GroupBy method groups the elements of a collection according
+// to a specified key selector function and projects the elements for each group
+// by using a specified function.
+func (q Query) GroupBy(
+ keySelector func(interface{}) interface{},
+ elementSelector func(interface{}) interface{},
+) Query {
+
return Query{
func() Iterator {
next := q.Iterate()
@@ -43,39 +46,3 @@ func (q Query) GroupBy(keySelector func(interface{}) interface{},
},
}
}
-
-// GroupByT is the typed version of GroupBy.
-//
-// - keySelectorFn is of type "func(TSource) TKey"
-// - elementSelectorFn is of type "func(TSource) TElement"
-//
-// NOTE: GroupBy has better performance than GroupByT.
-func (q Query) GroupByT(keySelectorFn interface{},
- elementSelectorFn interface{}) Query {
- keySelectorGenericFunc, err := newGenericFunc(
- "GroupByT", "keySelectorFn", keySelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- keySelectorFunc := func(item interface{}) interface{} {
- return keySelectorGenericFunc.Call(item)
- }
-
- elementSelectorGenericFunc, err := newGenericFunc(
- "GroupByT", "elementSelectorFn", elementSelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- elementSelectorFunc := func(item interface{}) interface{} {
- return elementSelectorGenericFunc.Call(item)
-
- }
-
- return q.GroupBy(keySelectorFunc, elementSelectorFunc)
-}
diff --git a/vendor/github.com/ahmetb/go-linq/groupjoin.go b/vendor/github.com/ahmetb/go-linq/groupjoin.go
index f9f8144..7a3b56b 100644
--- a/vendor/github.com/ahmetb/go-linq/groupjoin.go
+++ b/vendor/github.com/ahmetb/go-linq/groupjoin.go
@@ -1,27 +1,25 @@
package linq
-import "reflect"
-
// GroupJoin correlates the elements of two collections based on key equality,
// and groups the results.
//
-// This method produces hierarchical results, which means that elements from
-// outer query are paired with collections of matching elements from inner.
-// GroupJoin enables you to base your results on a whole set of matches for each
-// element of outer query.
+// This method produces hierarchical results, which means that elements from outer query
+// are paired with collections of matching elements from inner. GroupJoin enables you
+// to base your results on a whole set of matches for each element of outer query.
//
// The resultSelector function is called only one time for each outer element
-// together with a collection of all the inner elements that match the outer
-// element. This differs from the Join method, in which the result selector
-// function is invoked on pairs that contain one element from outer and one
-// element from inner.
+// together with a collection of all the inner elements that match the outer element.
+// This differs from the Join method, in which the result selector function is invoked
+// on pairs that contain one element from outer and one element from inner.
//
-// GroupJoin preserves the order of the elements of outer, and for each element
-// of outer, the order of the matching elements from inner.
-func (q Query) GroupJoin(inner Query,
+// GroupJoin preserves the order of the elements of outer, and for each element of outer,
+// the order of the matching elements from inner.
+func (q Query) GroupJoin(
+ inner Query,
outerKeySelector func(interface{}) interface{},
innerKeySelector func(interface{}) interface{},
- resultSelector func(outer interface{}, inners []interface{}) interface{}) Query {
+ resultSelector func(outer interface{}, inners []interface{}) interface{},
+) Query {
return Query{
Iterate: func() Iterator {
@@ -50,58 +48,3 @@ func (q Query) GroupJoin(inner Query,
},
}
}
-
-// GroupJoinT is the typed version of GroupJoin.
-//
-// - inner: The query to join to the outer query.
-// - outerKeySelectorFn is of type "func(TOuter) TKey"
-// - innerKeySelectorFn is of type "func(TInner) TKey"
-// - resultSelectorFn: is of type "func(TOuter, inners []TInner) TResult"
-//
-// NOTE: GroupJoin has better performance than GroupJoinT.
-func (q Query) GroupJoinT(inner Query,
- outerKeySelectorFn interface{},
- innerKeySelectorFn interface{},
- resultSelectorFn interface{}) Query {
- outerKeySelectorGenericFunc, err := newGenericFunc(
- "GroupJoinT", "outerKeySelectorFn", outerKeySelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- outerKeySelectorFunc := func(item interface{}) interface{} {
- return outerKeySelectorGenericFunc.Call(item)
- }
-
- innerKeySelectorFuncGenericFunc, err := newGenericFunc(
- "GroupJoinT", "innerKeySelectorFn", innerKeySelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- innerKeySelectorFunc := func(item interface{}) interface{} {
- return innerKeySelectorFuncGenericFunc.Call(item)
- }
-
- resultSelectorGenericFunc, err := newGenericFunc(
- "GroupJoinT", "resultSelectorFn", resultSelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- resultSelectorFunc := func(outer interface{}, inners []interface{}) interface{} {
- innerSliceType := reflect.MakeSlice(resultSelectorGenericFunc.Cache.TypesIn[1], 0, 0)
- innersSlicePointer := reflect.New(innerSliceType.Type())
- From(inners).ToSlice(innersSlicePointer.Interface())
- innersTyped := reflect.Indirect(innersSlicePointer).Interface()
- return resultSelectorGenericFunc.Call(outer, innersTyped)
- }
-
- return q.GroupJoin(inner, outerKeySelectorFunc, innerKeySelectorFunc, resultSelectorFunc)
-}
diff --git a/vendor/github.com/ahmetb/go-linq/intersect.go b/vendor/github.com/ahmetb/go-linq/intersect.go
index 511ed3b..6499bb8 100644
--- a/vendor/github.com/ahmetb/go-linq/intersect.go
+++ b/vendor/github.com/ahmetb/go-linq/intersect.go
@@ -2,8 +2,8 @@ package linq
// Intersect produces the set intersection of the source collection and the
// provided input collection. The intersection of two sets A and B is defined as
-// the set that contains all the elements of A that also appear in B, but no
-// other elements.
+// the set that contains all the elements of A that also appear in B,
+// but no other elements.
func (q Query) Intersect(q2 Query) Query {
return Query{
Iterate: func() Iterator {
@@ -31,12 +31,14 @@ func (q Query) Intersect(q2 Query) Query {
// IntersectBy produces the set intersection of the source collection and the
// provided input collection. The intersection of two sets A and B is defined as
-// the set that contains all the elements of A that also appear in B, but no
-// other elements.
+// the set that contains all the elements of A that also appear in B,
+// but no other elements.
//
// IntersectBy invokes a transform function on each element of both collections.
-func (q Query) IntersectBy(q2 Query,
- selector func(interface{}) interface{}) Query {
+func (q Query) IntersectBy(
+ q2 Query,
+ selector func(interface{}) interface{},
+) Query {
return Query{
Iterate: func() Iterator {
@@ -63,25 +65,3 @@ func (q Query) IntersectBy(q2 Query,
},
}
}
-
-// IntersectByT is the typed version of IntersectBy.
-//
-// - selectorFn is of type "func(TSource) TSource"
-//
-// NOTE: IntersectBy has better performance than IntersectByT.
-func (q Query) IntersectByT(q2 Query,
- selectorFn interface{}) Query {
- selectorGenericFunc, err := newGenericFunc(
- "IntersectByT", "selectorFn", selectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- selectorFunc := func(item interface{}) interface{} {
- return selectorGenericFunc.Call(item)
- }
-
- return q.IntersectBy(q2, selectorFunc)
-}
diff --git a/vendor/github.com/ahmetb/go-linq/join.go b/vendor/github.com/ahmetb/go-linq/join.go
index 68211a2..95cb835 100644
--- a/vendor/github.com/ahmetb/go-linq/join.go
+++ b/vendor/github.com/ahmetb/go-linq/join.go
@@ -2,18 +2,20 @@ package linq
// Join correlates the elements of two collection based on matching keys.
//
-// A join refers to the operation of correlating the elements of two sources of
-// information based on a common key. Join brings the two information sources
-// and the keys by which they are matched together in one method call. This
-// differs from the use of SelectMany, which requires more than one method call
+// A join refers to the operation of correlating the elements of two sources
+// of information based on a common key. Join brings the two information sources
+// and the keys by which they are matched together in one method call.
+// This differs from the use of SelectMany, which requires more than one method call
// to perform the same operation.
//
-// Join preserves the order of the elements of outer collection, and for each of
-// these elements, the order of the matching elements of inner.
-func (q Query) Join(inner Query,
+// Join preserves the order of the elements of outer collection,
+// and for each of these elements, the order of the matching elements of inner.
+func (q Query) Join(
+ inner Query,
outerKeySelector func(interface{}) interface{},
innerKeySelector func(interface{}) interface{},
- resultSelector func(outer interface{}, inner interface{}) interface{}) Query {
+ resultSelector func(outer interface{}, inner interface{}) interface{},
+) Query {
return Query{
Iterate: func() Iterator {
@@ -52,54 +54,3 @@ func (q Query) Join(inner Query,
},
}
}
-
-// JoinT is the typed version of Join.
-//
-// - outerKeySelectorFn is of type "func(TOuter) TKey"
-// - innerKeySelectorFn is of type "func(TInner) TKey"
-// - resultSelectorFn is of type "func(TOuter,TInner) TResult"
-//
-// NOTE: Join has better performance than JoinT.
-func (q Query) JoinT(inner Query,
- outerKeySelectorFn interface{},
- innerKeySelectorFn interface{},
- resultSelectorFn interface{}) Query {
- outerKeySelectorGenericFunc, err := newGenericFunc(
- "JoinT", "outerKeySelectorFn", outerKeySelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- outerKeySelectorFunc := func(item interface{}) interface{} {
- return outerKeySelectorGenericFunc.Call(item)
- }
-
- innerKeySelectorFuncGenericFunc, err := newGenericFunc(
- "JoinT", "innerKeySelectorFn",
- innerKeySelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- innerKeySelectorFunc := func(item interface{}) interface{} {
- return innerKeySelectorFuncGenericFunc.Call(item)
- }
-
- resultSelectorGenericFunc, err := newGenericFunc(
- "JoinT", "resultSelectorFn", resultSelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- resultSelectorFunc := func(outer interface{}, inner interface{}) interface{} {
- return resultSelectorGenericFunc.Call(outer, inner)
- }
-
- return q.Join(inner, outerKeySelectorFunc, innerKeySelectorFunc, resultSelectorFunc)
-}
diff --git a/vendor/github.com/ahmetb/go-linq/orderby.go b/vendor/github.com/ahmetb/go-linq/orderby.go
index 110559d..ff7f5ce 100644
--- a/vendor/github.com/ahmetb/go-linq/orderby.go
+++ b/vendor/github.com/ahmetb/go-linq/orderby.go
@@ -8,17 +8,18 @@ type order struct {
desc bool
}
-// OrderedQuery is the type returned from OrderBy, OrderByDescending ThenBy and
-// ThenByDescending functions.
+// OrderedQuery is the type returned from OrderBy, OrderByDescending
+// ThenBy and ThenByDescending functions.
type OrderedQuery struct {
Query
original Query
orders []order
}
-// OrderBy sorts the elements of a collection in ascending order. Elements are
-// sorted according to a key.
-func (q Query) OrderBy(selector func(interface{}) interface{}) OrderedQuery {
+// OrderBy sorts the elements of a collection in ascending order.
+// Elements are sorted according to a key.
+func (q Query) OrderBy(
+ selector func(interface{}) interface{}) OrderedQuery {
return OrderedQuery{
orders: []order{{selector: selector}},
original: q,
@@ -42,30 +43,10 @@ func (q Query) OrderBy(selector func(interface{}) interface{}) OrderedQuery {
}
}
-// OrderByT is the typed version of OrderBy.
-//
-// - selectorFn is of type "func(TSource) TKey"
-//
-// NOTE: OrderBy has better performance than OrderByT.
-func (q Query) OrderByT(selectorFn interface{}) OrderedQuery {
- selectorGenericFunc, err := newGenericFunc(
- "OrderByT", "selectorFn", selectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- selectorFunc := func(item interface{}) interface{} {
- return selectorGenericFunc.Call(item)
- }
-
- return q.OrderBy(selectorFunc)
-}
-
// OrderByDescending sorts the elements of a collection in descending order.
// Elements are sorted according to a key.
-func (q Query) OrderByDescending(selector func(interface{}) interface{}) OrderedQuery {
+func (q Query) OrderByDescending(
+ selector func(interface{}) interface{}) OrderedQuery {
return OrderedQuery{
orders: []order{{selector: selector, desc: true}},
original: q,
@@ -89,28 +70,9 @@ func (q Query) OrderByDescending(selector func(interface{}) interface{}) Ordered
}
}
-// OrderByDescendingT is the typed version of OrderByDescending.
-// - selectorFn is of type "func(TSource) TKey"
-// NOTE: OrderByDescending has better performance than OrderByDescendingT.
-func (q Query) OrderByDescendingT(selectorFn interface{}) OrderedQuery {
- selectorGenericFunc, err := newGenericFunc(
- "OrderByDescendingT", "selectorFn", selectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- selectorFunc := func(item interface{}) interface{} {
- return selectorGenericFunc.Call(item)
- }
-
- return q.OrderByDescending(selectorFunc)
-}
-
-// ThenBy performs a subsequent ordering of the elements in a collection in
-// ascending order. This method enables you to specify multiple sort criteria by
-// applying any number of ThenBy or ThenByDescending methods.
+// ThenBy performs a subsequent ordering of the elements in a collection
+// in ascending order. This method enables you to specify multiple sort criteria
+// by applying any number of ThenBy or ThenByDescending methods.
func (oq OrderedQuery) ThenBy(
selector func(interface{}) interface{}) OrderedQuery {
return OrderedQuery{
@@ -136,29 +98,11 @@ func (oq OrderedQuery) ThenBy(
}
}
-// ThenByT is the typed version of ThenBy.
-// - selectorFn is of type "func(TSource) TKey"
-// NOTE: ThenBy has better performance than ThenByT.
-func (oq OrderedQuery) ThenByT(selectorFn interface{}) OrderedQuery {
- selectorGenericFunc, err := newGenericFunc(
- "ThenByT", "selectorFn", selectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- selectorFunc := func(item interface{}) interface{} {
- return selectorGenericFunc.Call(item)
- }
-
- return oq.ThenBy(selectorFunc)
-}
-
-// ThenByDescending performs a subsequent ordering of the elements in a
-// collection in descending order. This method enables you to specify multiple
-// sort criteria by applying any number of ThenBy or ThenByDescending methods.
-func (oq OrderedQuery) ThenByDescending(selector func(interface{}) interface{}) OrderedQuery {
+// ThenByDescending performs a subsequent ordering of the elements in a collection
+// in descending order. This method enables you to specify multiple sort criteria
+// by applying any number of ThenBy or ThenByDescending methods.
+func (oq OrderedQuery) ThenByDescending(
+ selector func(interface{}) interface{}) OrderedQuery {
return OrderedQuery{
orders: append(oq.orders, order{selector: selector, desc: true}),
original: oq.original,
@@ -182,32 +126,10 @@ func (oq OrderedQuery) ThenByDescending(selector func(interface{}) interface{})
}
}
-// ThenByDescendingT is the typed version of ThenByDescending.
-// - selectorFn is of type "func(TSource) TKey"
-// NOTE: ThenByDescending has better performance than ThenByDescendingT.
-func (oq OrderedQuery) ThenByDescendingT(selectorFn interface{}) OrderedQuery {
- selectorFunc, ok := selectorFn.(func(interface{}) interface{})
- if !ok {
- selectorGenericFunc, err := newGenericFunc(
- "ThenByDescending", "selectorFn", selectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- selectorFunc = func(item interface{}) interface{} {
- return selectorGenericFunc.Call(item)
- }
- }
- return oq.ThenByDescending(selectorFunc)
-}
-
-// Sort returns a new query by sorting elements with provided less function in
-// ascending order. The comparer function should return true if the parameter i
-// is less than j. While this method is uglier than chaining OrderBy,
-// OrderByDescending, ThenBy and ThenByDescending methods, it's performance is
-// much better.
+// Sort returns a new query by sorting elements with provided less function
+// in ascending order. The comparer function should return true if the parameter i
+// is less than j. While this method is uglier than chaining OrderBy, OrderByDescending,
+// ThenBy and ThenByDescending methods, it's performance is much better.
func (q Query) Sort(less func(i, j interface{}) bool) Query {
return Query{
Iterate: func() Iterator {
@@ -228,25 +150,6 @@ func (q Query) Sort(less func(i, j interface{}) bool) Query {
}
}
-// SortT is the typed version of Sort.
-// - lessFn is of type "func(TSource,TSource) bool"
-// NOTE: Sort has better performance than SortT.
-func (q Query) SortT(lessFn interface{}) Query {
- lessGenericFunc, err := newGenericFunc(
- "SortT", "lessFn", lessFn,
- simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
-
- lessFunc := func(i, j interface{}) bool {
- return lessGenericFunc.Call(i, j).(bool)
- }
-
- return q.Sort(lessFunc)
-}
-
type sorter struct {
items []interface{}
less func(i, j interface{}) bool
@@ -270,10 +173,6 @@ func (q Query) sort(orders []order) (r []interface{}) {
r = append(r, item)
}
- if len(r) == 0 {
- return
- }
-
for i, j := range orders {
orders[i].compare = getComparer(j.selector(r[0]))
}
diff --git a/vendor/github.com/ahmetb/go-linq/result.go b/vendor/github.com/ahmetb/go-linq/result.go
index 34e47ab..979be93 100644
--- a/vendor/github.com/ahmetb/go-linq/result.go
+++ b/vendor/github.com/ahmetb/go-linq/result.go
@@ -18,27 +18,6 @@ func (q Query) All(predicate func(interface{}) bool) bool {
return true
}
-// AllT is the typed version of All.
-//
-// - predicateFn is of type "func(TSource) bool"
-//
-// NOTE: All has better performance than AllT.
-func (q Query) AllT(predicateFn interface{}) bool {
-
- predicateGenericFunc, err := newGenericFunc(
- "AllT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
- predicateFunc := func(item interface{}) bool {
- return predicateGenericFunc.Call(item).(bool)
- }
-
- return q.All(predicateFunc)
-}
-
// Any determines whether any element of a collection exists.
func (q Query) Any() bool {
_, ok := q.Iterate()()
@@ -58,28 +37,6 @@ func (q Query) AnyWith(predicate func(interface{}) bool) bool {
return false
}
-// AnyWithT is the typed version of AnyWith.
-//
-// - predicateFn is of type "func(TSource) bool"
-//
-// NOTE: AnyWith has better performance than AnyWithT.
-func (q Query) AnyWithT(predicateFn interface{}) bool {
-
- predicateGenericFunc, err := newGenericFunc(
- "AnyWithT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
-
- predicateFunc := func(item interface{}) bool {
- return predicateGenericFunc.Call(item).(bool)
- }
-
- return q.AnyWith(predicateFunc)
-}
-
// Average computes the average of a collection of numeric values.
func (q Query) Average() (r float64) {
next := q.Iterate()
@@ -147,8 +104,8 @@ func (q Query) Count() (r int) {
return
}
-// CountWith returns a number that represents how many elements in the specified
-// collection satisfy a condition.
+// CountWith returns a number that represents how many elements
+// in the specified collection satisfy a condition.
func (q Query) CountWith(predicate func(interface{}) bool) (r int) {
next := q.Iterate()
@@ -161,36 +118,14 @@ func (q Query) CountWith(predicate func(interface{}) bool) (r int) {
return
}
-// CountWithT is the typed version of CountWith.
-//
-// - predicateFn is of type "func(TSource) bool"
-//
-// NOTE: CountWith has better performance than CountWithT.
-func (q Query) CountWithT(predicateFn interface{}) int {
-
- predicateGenericFunc, err := newGenericFunc(
- "CountWithT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
-
- predicateFunc := func(item interface{}) bool {
- return predicateGenericFunc.Call(item).(bool)
- }
-
- return q.CountWith(predicateFunc)
-}
-
// First returns the first element of a collection.
func (q Query) First() interface{} {
item, _ := q.Iterate()()
return item
}
-// FirstWith returns the first element of a collection that satisfies a
-// specified condition.
+// FirstWith returns the first element of a collection that satisfies
+// a specified condition.
func (q Query) FirstWith(predicate func(interface{}) bool) interface{} {
next := q.Iterate()
@@ -203,99 +138,6 @@ func (q Query) FirstWith(predicate func(interface{}) bool) interface{} {
return nil
}
-// FirstWithT is the typed version of FirstWith.
-//
-// - predicateFn is of type "func(TSource) bool"
-//
-// NOTE: FirstWith has better performance than FirstWithT.
-func (q Query) FirstWithT(predicateFn interface{}) interface{} {
-
- predicateGenericFunc, err := newGenericFunc(
- "FirstWithT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
-
- predicateFunc := func(item interface{}) bool {
- return predicateGenericFunc.Call(item).(bool)
- }
-
- return q.FirstWith(predicateFunc)
-}
-
-// ForEach performs the specified action on each element of a collection.
-func (q Query) ForEach(action func(interface{})) {
- next := q.Iterate()
-
- for item, ok := next(); ok; item, ok = next() {
- action(item)
- }
-}
-
-// ForEachT is the typed version of ForEach.
-//
-// - actionFn is of type "func(TSource)"
-//
-// NOTE: ForEach has better performance than ForEachT.
-func (q Query) ForEachT(actionFn interface{}) {
- actionGenericFunc, err := newGenericFunc(
- "ForEachT", "actionFn", actionFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), nil),
- )
-
- if err != nil {
- panic(err)
- }
-
- actionFunc := func(item interface{}) {
- actionGenericFunc.Call(item)
- }
-
- q.ForEach(actionFunc)
-}
-
-// ForEachIndexed performs the specified action on each element of a collection.
-//
-// The first argument to action represents the zero-based index of that
-// element in the source collection. This can be useful if the elements are in a
-// known order and you want to do something with an element at a particular
-// index, for example. It can also be useful if you want to retrieve the index
-// of one or more elements. The second argument to action represents the
-// element to process.
-func (q Query) ForEachIndexed(action func(int, interface{})) {
- next := q.Iterate()
- index := 0
-
- for item, ok := next(); ok; item, ok = next() {
- action(index, item)
- index++
- }
-}
-
-// ForEachIndexedT is the typed version of ForEachIndexed.
-//
-// - actionFn is of type "func(int, TSource)"
-//
-// NOTE: ForEachIndexed has better performance than ForEachIndexedT.
-func (q Query) ForEachIndexedT(actionFn interface{}) {
- actionGenericFunc, err := newGenericFunc(
- "ForEachIndexedT", "actionFn", actionFn,
- simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), nil),
- )
-
- if err != nil {
- panic(err)
- }
-
- actionFunc := func(index int, item interface{}) {
- actionGenericFunc.Call(index, item)
- }
-
- q.ForEachIndexed(actionFunc)
-}
-
// Last returns the last element of a collection.
func (q Query) Last() (r interface{}) {
next := q.Iterate()
@@ -307,8 +149,8 @@ func (q Query) Last() (r interface{}) {
return
}
-// LastWith returns the last element of a collection that satisfies a specified
-// condition.
+// LastWith returns the last element of a collection that satisfies
+// a specified condition.
func (q Query) LastWith(predicate func(interface{}) bool) (r interface{}) {
next := q.Iterate()
@@ -321,28 +163,6 @@ func (q Query) LastWith(predicate func(interface{}) bool) (r interface{}) {
return
}
-// LastWithT is the typed version of LastWith.
-//
-// - predicateFn is of type "func(TSource) bool"
-//
-// NOTE: LastWith has better performance than LastWithT.
-func (q Query) LastWithT(predicateFn interface{}) interface{} {
-
- predicateGenericFunc, err := newGenericFunc(
- "LastWithT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
-
- predicateFunc := func(item interface{}) bool {
- return predicateGenericFunc.Call(item).(bool)
- }
-
- return q.LastWith(predicateFunc)
-}
-
// Max returns the maximum value in a collection of values.
func (q Query) Max() (r interface{}) {
next := q.Iterate()
@@ -410,8 +230,8 @@ func (q Query) SequenceEqual(q2 Query) bool {
return !ok2
}
-// Single returns the only element of a collection, and nil if there is not
-// exactly one element in the collection.
+// Single returns the only element of a collection, and nil
+// if there is not exactly one element in the collection.
func (q Query) Single() interface{} {
next := q.Iterate()
item, ok := next()
@@ -427,8 +247,8 @@ func (q Query) Single() interface{} {
return item
}
-// SingleWith returns the only element of a collection that satisfies a
-// specified condition, and nil if more than one such element exists.
+// SingleWith returns the only element of a collection that satisfies
+// a specified condition, and nil if more than one such element exists.
func (q Query) SingleWith(predicate func(interface{}) bool) (r interface{}) {
next := q.Iterate()
found := false
@@ -447,31 +267,10 @@ func (q Query) SingleWith(predicate func(interface{}) bool) (r interface{}) {
return
}
-// SingleWithT is the typed version of SingleWith.
-//
-// - predicateFn is of type "func(TSource) bool"
-//
-// NOTE: SingleWith has better performance than SingleWithT.
-func (q Query) SingleWithT(predicateFn interface{}) interface{} {
- predicateGenericFunc, err := newGenericFunc(
- "SingleWithT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
-
- predicateFunc := func(item interface{}) bool {
- return predicateGenericFunc.Call(item).(bool)
- }
-
- return q.SingleWith(predicateFunc)
-}
-
// SumInts computes the sum of a collection of numeric values.
//
-// Values can be of any integer type: int, int8, int16, int32, int64. The result
-// is int64. Method returns zero if collection contains no elements.
+// Values can be of any integer type: int, int8, int16, int32, int64.
+// The result is int64. Method returns zero if collection contains no elements.
func (q Query) SumInts() (r int64) {
next := q.Iterate()
item, ok := next()
@@ -491,9 +290,8 @@ func (q Query) SumInts() (r int64) {
// SumUInts computes the sum of a collection of numeric values.
//
-// Values can be of any unsigned integer type: uint, uint8, uint16, uint32,
-// uint64. The result is uint64. Method returns zero if collection contains no
-// elements.
+// Values can be of any unsigned integer type: uint, uint8, uint16, uint32, uint64.
+// The result is uint64. Method returns zero if collection contains no elements.
func (q Query) SumUInts() (r uint64) {
next := q.Iterate()
item, ok := next()
@@ -532,8 +330,8 @@ func (q Query) SumFloats() (r float64) {
return
}
-// ToChannel iterates over a collection and outputs each element to a channel,
-// then closes it.
+// ToChannel iterates over a collection and outputs each element
+// to a channel, then closes it.
func (q Query) ToChannel(result chan<- interface{}) {
next := q.Iterate()
@@ -545,9 +343,8 @@ func (q Query) ToChannel(result chan<- interface{}) {
}
// ToMap iterates over a collection and populates result map with elements.
-// Collection elements have to be of KeyValue type to use this method. To
-// populate a map with elements of different type use ToMapBy method. ToMap
-// doesn't empty the result map before populating it.
+// Collection elements have to be of KeyValue type to use this method.
+// To populate a map with elements of different type use ToMapBy method.
func (q Query) ToMap(result interface{}) {
q.ToMapBy(
result,
@@ -559,14 +356,15 @@ func (q Query) ToMap(result interface{}) {
})
}
-// ToMapBy iterates over a collection and populates the result map with
-// elements. Functions keySelector and valueSelector are executed for each
-// element of the collection to generate key and value for the map. Generated
-// key and value types must be assignable to the map's key and value types.
-// ToMapBy doesn't empty the result map before populating it.
-func (q Query) ToMapBy(result interface{},
+// ToMapBy iterates over a collection and populates result map with elements.
+// Functions keySelector and valueSelector are executed for each element of the collection
+// to generate key and value for the map. Generated key and value types must be assignable
+// to the map's key and value types.
+func (q Query) ToMapBy(
+ result interface{},
keySelector func(interface{}) interface{},
- valueSelector func(interface{}) interface{}) {
+ valueSelector func(interface{}) interface{},
+) {
res := reflect.ValueOf(result)
m := reflect.Indirect(res)
next := q.Iterate()
@@ -581,78 +379,16 @@ func (q Query) ToMapBy(result interface{},
res.Elem().Set(m)
}
-// ToMapByT is the typed version of ToMapBy.
-//
-// - keySelectorFn is of type "func(TSource)TKey"
-// - valueSelectorFn is of type "func(TSource)TValue"
-//
-// NOTE: ToMapBy has better performance than ToMapByT.
-func (q Query) ToMapByT(result interface{},
- keySelectorFn interface{}, valueSelectorFn interface{}) {
- keySelectorGenericFunc, err := newGenericFunc(
- "ToMapByT", "keySelectorFn", keySelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- keySelectorFunc := func(item interface{}) interface{} {
- return keySelectorGenericFunc.Call(item)
- }
-
- valueSelectorGenericFunc, err := newGenericFunc(
- "ToMapByT", "valueSelectorFn", valueSelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- valueSelectorFunc := func(item interface{}) interface{} {
- return valueSelectorGenericFunc.Call(item)
- }
-
- q.ToMapBy(result, keySelectorFunc, valueSelectorFunc)
-}
-
-// ToSlice iterates over a collection and saves the results in the slice pointed
-// by v. It overwrites the existing slice, starting from index 0.
-//
-// If the slice pointed by v has sufficient capacity, v will be pointed to a
-// resliced slice. If it does not, a new underlying array will be allocated and
-// v will point to it.
-func (q Query) ToSlice(v interface{}) {
- res := reflect.ValueOf(v)
+// ToSlice iterates over a collection and populates result slice with elements.
+// Collection elements must be assignable to the slice's element type.
+func (q Query) ToSlice(result interface{}) {
+ res := reflect.ValueOf(result)
slice := reflect.Indirect(res)
-
- cap := slice.Cap()
- res.Elem().Set(slice.Slice(0, cap)) // make len(slice)==cap(slice) from now on
-
next := q.Iterate()
- index := 0
+
for item, ok := next(); ok; item, ok = next() {
- if index >= cap {
- slice, cap = grow(slice)
- }
- slice.Index(index).Set(reflect.ValueOf(item))
- index++
+ slice = reflect.Append(slice, reflect.ValueOf(item))
}
- // reslice the len(res)==cap(res) actual res size
- res.Elem().Set(slice.Slice(0, index))
-}
-
-// grow grows the slice s by doubling its capacity, then it returns the new
-// slice (resliced to its full capacity) and the new capacity.
-func grow(s reflect.Value) (v reflect.Value, newCap int) {
- cap := s.Cap()
- if cap == 0 {
- cap = 1
- } else {
- cap *= 2
- }
- newSlice := reflect.MakeSlice(s.Type(), cap, cap)
- reflect.Copy(newSlice, s)
- return newSlice, cap
+ res.Elem().Set(slice)
}
diff --git a/vendor/github.com/ahmetb/go-linq/reverse.go b/vendor/github.com/ahmetb/go-linq/reverse.go
index 8716c22..eaacb9f 100644
--- a/vendor/github.com/ahmetb/go-linq/reverse.go
+++ b/vendor/github.com/ahmetb/go-linq/reverse.go
@@ -2,9 +2,9 @@ package linq
// Reverse inverts the order of the elements in a collection.
//
-// Unlike OrderBy, this sorting method does not consider the actual values
-// themselves in determining the order. Rather, it just returns the elements in
-// the reverse order from which they are produced by the underlying source.
+// Unlike OrderBy, this sorting method does not consider the actual values themselves
+// in determining the order. Rather, it just returns the elements in the reverse order
+// from which they are produced by the underlying source.
func (q Query) Reverse() Query {
return Query{
Iterate: func() Iterator {
diff --git a/vendor/github.com/ahmetb/go-linq/select.go b/vendor/github.com/ahmetb/go-linq/select.go
index 5dc8cc7..e607229 100644
--- a/vendor/github.com/ahmetb/go-linq/select.go
+++ b/vendor/github.com/ahmetb/go-linq/select.go
@@ -1,16 +1,17 @@
package linq
-// Select projects each element of a collection into a new form. Returns a query
-// with the result of invoking the transform function on each element of
-// original source.
+// Select projects each element of a collection into a new form.
+// Returns a query with the result of invoking the transform function
+// on each element of original source.
//
-// This projection method requires the transform function, selector, to produce
-// one value for each value in the source collection. If selector returns a
-// value that is itself a collection, it is up to the consumer to traverse the
-// subcollections manually. In such a situation, it might be better for your
-// query to return a single coalesced collection of values. To achieve this, use
-// the SelectMany method instead of Select. Although SelectMany works similarly
-// to Select, it differs in that the transform function returns a collection
+// This projection method requires the transform function, selector,
+// to produce one value for each value in the source collection.
+// If selector returns a value that is itself a collection,
+// it is up to the consumer to traverse the subcollections manually.
+// In such a situation, it might be better for your query to return a single
+// coalesced collection of values. To achieve this, use the SelectMany method
+// instead of Select. Although SelectMany works similarly to Select,
+// it differs in that the transform function returns a collection
// that is then expanded by SelectMany before it is returned.
func (q Query) Select(selector func(interface{}) interface{}) Query {
return Query{
@@ -30,44 +31,24 @@ func (q Query) Select(selector func(interface{}) interface{}) Query {
}
}
-// SelectT is the typed version of Select.
-// - selectorFn is of type "func(TSource)TResult"
-// NOTE: Select has better performance than SelectT.
-func (q Query) SelectT(selectorFn interface{}) Query {
-
- selectGenericFunc, err := newGenericFunc(
- "SelectT", "selectorFn", selectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- selectorFunc := func(item interface{}) interface{} {
- return selectGenericFunc.Call(item)
- }
-
- return q.Select(selectorFunc)
-}
-
-// SelectIndexed projects each element of a collection into a new form by
-// incorporating the element's index. Returns a query with the result of
-// invoking the transform function on each element of original source.
+// SelectIndexed projects each element of a collection into a new form
+// by incorporating the element's index. Returns a query with the result
+// of invoking the transform function on each element of original source.
//
-// The first argument to selector represents the zero-based index of that
-// element in the source collection. This can be useful if the elements are in a
-// known order and you want to do something with an element at a particular
-// index, for example. It can also be useful if you want to retrieve the index
-// of one or more elements. The second argument to selector represents the
-// element to process.
+// The first argument to selector represents the zero-based index of that element
+// in the source collection. This can be useful if the elements are in a known order
+// and you want to do something with an element at a particular index,
+// for example. It can also be useful if you want to retrieve the index of one
+// or more elements. The second argument to selector represents the element to process.
//
-// This projection method requires the transform function, selector, to produce
-// one value for each value in the source collection. If selector returns a
-// value that is itself a collection, it is up to the consumer to traverse the
-// subcollections manually. In such a situation, it might be better for your
-// query to return a single coalesced collection of values. To achieve this, use
-// the SelectMany method instead of Select. Although SelectMany works similarly
-// to Select, it differs in that the transform function returns a collection
+// This projection method requires the transform function, selector,
+// to produce one value for each value in the source collection.
+// If selector returns a value that is itself a collection,
+// it is up to the consumer to traverse the subcollections manually.
+// In such a situation, it might be better for your query to return a single
+// coalesced collection of values. To achieve this, use the SelectMany method
+// instead of Select. Although SelectMany works similarly to Select,
+// it differs in that the transform function returns a collection
// that is then expanded by SelectMany before it is returned.
func (q Query) SelectIndexed(selector func(int, interface{}) interface{}) Query {
return Query{
@@ -88,22 +69,3 @@ func (q Query) SelectIndexed(selector func(int, interface{}) interface{}) Query
},
}
}
-
-// SelectIndexedT is the typed version of SelectIndexed.
-// - selectorFn is of type "func(int,TSource)TResult"
-// NOTE: SelectIndexed has better performance than SelectIndexedT.
-func (q Query) SelectIndexedT(selectorFn interface{}) Query {
- selectGenericFunc, err := newGenericFunc(
- "SelectIndexedT", "selectorFn", selectorFn,
- simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- selectorFunc := func(index int, item interface{}) interface{} {
- return selectGenericFunc.Call(index, item)
- }
-
- return q.SelectIndexed(selectorFunc)
-}
diff --git a/vendor/github.com/ahmetb/go-linq/selectmany.go b/vendor/github.com/ahmetb/go-linq/selectmany.go
index 74fa671..25ea8c3 100644
--- a/vendor/github.com/ahmetb/go-linq/selectmany.go
+++ b/vendor/github.com/ahmetb/go-linq/selectmany.go
@@ -32,37 +32,14 @@ func (q Query) SelectMany(selector func(interface{}) Query) Query {
}
}
-// SelectManyT is the typed version of SelectMany.
+// SelectManyIndexed projects each element of a collection to a Query, iterates and
+// flattens the resulting collection into one collection.
//
-// - selectorFn is of type "func(TSource)Query"
-//
-// NOTE: SelectMany has better performance than SelectManyT.
-func (q Query) SelectManyT(selectorFn interface{}) Query {
-
- selectManyGenericFunc, err := newGenericFunc(
- "SelectManyT", "selectorFn", selectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(Query))),
- )
- if err != nil {
- panic(err)
- }
-
- selectorFunc := func(inner interface{}) Query {
- return selectManyGenericFunc.Call(inner).(Query)
- }
- return q.SelectMany(selectorFunc)
-
-}
-
-// SelectManyIndexed projects each element of a collection to a Query, iterates
-// and flattens the resulting collection into one collection.
-//
-// The first argument to selector represents the zero-based index of that
-// element in the source collection. This can be useful if the elements are in a
-// known order and you want to do something with an element at a particular
-// index, for example. It can also be useful if you want to retrieve the index
-// of one or more elements. The second argument to selector represents the
-// element to process.
+// The first argument to selector represents the zero-based index of that element
+// in the source collection. This can be useful if the elements are in a known order
+// and you want to do something with an element at a particular index, for example.
+// It can also be useful if you want to retrieve the index of one or more elements.
+// The second argument to selector represents the element to process.
func (q Query) SelectManyIndexed(selector func(int, interface{}) Query) Query {
return Query{
Iterate: func() Iterator {
@@ -95,33 +72,13 @@ func (q Query) SelectManyIndexed(selector func(int, interface{}) Query) Query {
}
}
-// SelectManyIndexedT is the typed version of SelectManyIndexed.
-//
-// - selectorFn is of type "func(int,TSource)Query"
-//
-// NOTE: SelectManyIndexed has better performance than SelectManyIndexedT.
-func (q Query) SelectManyIndexedT(selectorFn interface{}) Query {
-
- selectManyIndexedGenericFunc, err := newGenericFunc(
- "SelectManyIndexedT", "selectorFn", selectorFn,
- simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(Query))),
- )
- if err != nil {
- panic(err)
- }
-
- selectorFunc := func(index int, inner interface{}) Query {
- return selectManyIndexedGenericFunc.Call(index, inner).(Query)
- }
-
- return q.SelectManyIndexed(selectorFunc)
-}
-
// SelectManyBy projects each element of a collection to a Query, iterates and
-// flattens the resulting collection into one collection, and invokes a result
-// selector function on each element therein.
-func (q Query) SelectManyBy(selector func(interface{}) Query,
- resultSelector func(interface{}, interface{}) interface{}) Query {
+// flattens the resulting collection into one collection, and invokes
+// a result selector function on each element therein.
+func (q Query) SelectManyBy(
+ selector func(interface{}) Query,
+ resultSelector func(interface{}, interface{}) interface{},
+) Query {
return Query{
Iterate: func() Iterator {
@@ -146,53 +103,18 @@ func (q Query) SelectManyBy(selector func(interface{}) Query,
}
}
- item = resultSelector(item, outer)
+ item = resultSelector(outer, item)
return
}
},
}
}
-// SelectManyByT is the typed version of SelectManyBy.
-//
-// - selectorFn is of type "func(TSource)Query"
-// - resultSelectorFn is of type "func(TSource,TCollection)TResult"
-//
-// NOTE: SelectManyBy has better performance than SelectManyByT.
-func (q Query) SelectManyByT(selectorFn interface{},
- resultSelectorFn interface{}) Query {
-
- selectorGenericFunc, err := newGenericFunc(
- "SelectManyByT", "selectorFn", selectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(Query))),
- )
- if err != nil {
- panic(err)
- }
-
- selectorFunc := func(outer interface{}) Query {
- return selectorGenericFunc.Call(outer).(Query)
- }
-
- resultSelectorGenericFunc, err := newGenericFunc(
- "SelectManyByT", "resultSelectorFn", resultSelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- resultSelectorFunc := func(outer interface{}, item interface{}) interface{} {
- return resultSelectorGenericFunc.Call(outer, item)
- }
-
- return q.SelectManyBy(selectorFunc, resultSelectorFunc)
-}
-
-// SelectManyByIndexed projects each element of a collection to a Query,
-// iterates and flattens the resulting collection into one collection, and
-// invokes a result selector function on each element therein. The index of each
-// source element is used in the intermediate projected form of that element.
+// SelectManyByIndexed projects each element of a collection to a Query, iterates and
+// flattens the resulting collection into one collection, and invokes
+// a result selector function on each element therein.
+// The index of each source element is used in the intermediate projected form
+// of that element.
func (q Query) SelectManyByIndexed(selector func(int, interface{}) Query,
resultSelector func(interface{}, interface{}) interface{}) Query {
@@ -221,45 +143,9 @@ func (q Query) SelectManyByIndexed(selector func(int, interface{}) Query,
}
}
- item = resultSelector(item, outer)
+ item = resultSelector(outer, item)
return
}
},
}
}
-
-// SelectManyByIndexedT is the typed version of SelectManyByIndexed.
-//
-// - selectorFn is of type "func(int,TSource)Query"
-// - resultSelectorFn is of type "func(TSource,TCollection)TResult"
-//
-// NOTE: SelectManyByIndexed has better performance than
-// SelectManyByIndexedT.
-func (q Query) SelectManyByIndexedT(selectorFn interface{},
- resultSelectorFn interface{}) Query {
- selectorGenericFunc, err := newGenericFunc(
- "SelectManyByIndexedT", "selectorFn", selectorFn,
- simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(Query))),
- )
- if err != nil {
- panic(err)
- }
-
- selectorFunc := func(index int, outer interface{}) Query {
- return selectorGenericFunc.Call(index, outer).(Query)
- }
-
- resultSelectorGenericFunc, err := newGenericFunc(
- "SelectManyByIndexedT", "resultSelectorFn", resultSelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- resultSelectorFunc := func(outer interface{}, item interface{}) interface{} {
- return resultSelectorGenericFunc.Call(outer, item)
- }
-
- return q.SelectManyByIndexed(selectorFunc, resultSelectorFunc)
-}
diff --git a/vendor/github.com/ahmetb/go-linq/skip.go b/vendor/github.com/ahmetb/go-linq/skip.go
index 0fb05d3..1110ae5 100644
--- a/vendor/github.com/ahmetb/go-linq/skip.go
+++ b/vendor/github.com/ahmetb/go-linq/skip.go
@@ -1,7 +1,7 @@
package linq
-// Skip bypasses a specified number of elements in a collection and then returns
-// the remaining elements.
+// Skip bypasses a specified number of elements in a collection
+// and then returns the remaining elements.
func (q Query) Skip(count int) Query {
return Query{
Iterate: func() Iterator {
@@ -22,13 +22,13 @@ func (q Query) Skip(count int) Query {
}
}
-// SkipWhile bypasses elements in a collection as long as a specified condition
-// is true and then returns the remaining elements.
+// SkipWhile bypasses elements in a collection as long as a specified condition is true
+// and then returns the remaining elements.
//
-// This method tests each element by using predicate and skips the element if
-// the result is true. After the predicate function returns false for an
-// element, that element and the remaining elements in source are returned and
-// there are no more invocations of predicate.
+// This method tests each element by using predicate and skips the element
+// if the result is true. After the predicate function returns false for an element,
+// that element and the remaining elements in source are returned
+// and there are no more invocations of predicate.
func (q Query) SkipWhile(predicate func(interface{}) bool) Query {
return Query{
Iterate: func() Iterator {
@@ -54,36 +54,14 @@ func (q Query) SkipWhile(predicate func(interface{}) bool) Query {
}
}
-// SkipWhileT is the typed version of SkipWhile.
+// SkipWhileIndexed bypasses elements in a collection as long as a specified condition
+// is true and then returns the remaining elements. The element's index is used
+// in the logic of the predicate function.
//
-// - predicateFn is of type "func(TSource)bool"
-//
-// NOTE: SkipWhile has better performance than SkipWhileT.
-func (q Query) SkipWhileT(predicateFn interface{}) Query {
-
- predicateGenericFunc, err := newGenericFunc(
- "SkipWhileT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
-
- predicateFunc := func(item interface{}) bool {
- return predicateGenericFunc.Call(item).(bool)
- }
-
- return q.SkipWhile(predicateFunc)
-}
-
-// SkipWhileIndexed bypasses elements in a collection as long as a specified
-// condition is true and then returns the remaining elements. The element's
-// index is used in the logic of the predicate function.
-//
-// This method tests each element by using predicate and skips the element if
-// the result is true. After the predicate function returns false for an
-// element, that element and the remaining elements in source are returned and
-// there are no more invocations of predicate.
+// This method tests each element by using predicate and skips the element
+// if the result is true. After the predicate function returns false for an element,
+// that element and the remaining elements in source are returned
+// and there are no more invocations of predicate.
func (q Query) SkipWhileIndexed(predicate func(int, interface{}) bool) Query {
return Query{
Iterate: func() Iterator {
@@ -111,24 +89,3 @@ func (q Query) SkipWhileIndexed(predicate func(int, interface{}) bool) Query {
},
}
}
-
-// SkipWhileIndexedT is the typed version of SkipWhileIndexed.
-//
-// - predicateFn is of type "func(int,TSource)bool"
-//
-// NOTE: SkipWhileIndexed has better performance than SkipWhileIndexedT.
-func (q Query) SkipWhileIndexedT(predicateFn interface{}) Query {
- predicateGenericFunc, err := newGenericFunc(
- "SkipWhileIndexedT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
-
- predicateFunc := func(index int, item interface{}) bool {
- return predicateGenericFunc.Call(index, item).(bool)
- }
-
- return q.SkipWhileIndexed(predicateFunc)
-}
diff --git a/vendor/github.com/ahmetb/go-linq/take.go b/vendor/github.com/ahmetb/go-linq/take.go
index c2707e5..d21fc96 100644
--- a/vendor/github.com/ahmetb/go-linq/take.go
+++ b/vendor/github.com/ahmetb/go-linq/take.go
@@ -1,7 +1,6 @@
package linq
-// Take returns a specified number of contiguous elements from the start of a
-// collection.
+// Take returns a specified number of contiguous elements from the start of a collection.
func (q Query) Take(count int) Query {
return Query{
Iterate: func() Iterator {
@@ -20,8 +19,8 @@ func (q Query) Take(count int) Query {
}
}
-// TakeWhile returns elements from a collection as long as a specified condition
-// is true, and then skips the remaining elements.
+// TakeWhile returns elements from a collection as long as a specified condition is true,
+// and then skips the remaining elements.
func (q Query) TakeWhile(predicate func(interface{}) bool) Query {
return Query{
Iterate: func() Iterator {
@@ -50,33 +49,10 @@ func (q Query) TakeWhile(predicate func(interface{}) bool) Query {
}
}
-// TakeWhileT is the typed version of TakeWhile.
-//
-// - predicateFn is of type "func(TSource)bool"
-//
-// NOTE: TakeWhile has better performance than TakeWhileT.
-func (q Query) TakeWhileT(predicateFn interface{}) Query {
-
- predicateGenericFunc, err := newGenericFunc(
- "TakeWhileT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
-
- predicateFunc := func(item interface{}) bool {
- return predicateGenericFunc.Call(item).(bool)
- }
-
- return q.TakeWhile(predicateFunc)
-}
-
-// TakeWhileIndexed returns elements from a collection as long as a specified
-// condition is true. The element's index is used in the logic of the predicate
-// function. The first argument of predicate represents the zero-based index of
-// the element within collection. The second argument represents the element to
-// test.
+// TakeWhileIndexed returns elements from a collection as long as a specified condition
+// is true. The element's index is used in the logic of the predicate function.
+// The first argument of predicate represents the zero-based index of the element
+// within collection. The second argument represents the element to test.
func (q Query) TakeWhileIndexed(predicate func(int, interface{}) bool) Query {
return Query{
Iterate: func() Iterator {
@@ -106,24 +82,3 @@ func (q Query) TakeWhileIndexed(predicate func(int, interface{}) bool) Query {
},
}
}
-
-// TakeWhileIndexedT is the typed version of TakeWhileIndexed.
-//
-// - predicateFn is of type "func(int,TSource)bool"
-//
-// NOTE: TakeWhileIndexed has better performance than TakeWhileIndexedT.
-func (q Query) TakeWhileIndexedT(predicateFn interface{}) Query {
- whereFunc, err := newGenericFunc(
- "TakeWhileIndexedT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
-
- predicateFunc := func(index int, item interface{}) bool {
- return whereFunc.Call(index, item).(bool)
- }
-
- return q.TakeWhileIndexed(predicateFunc)
-}
diff --git a/vendor/github.com/ahmetb/go-linq/union.go b/vendor/github.com/ahmetb/go-linq/union.go
index 717b83b..9ca4b65 100644
--- a/vendor/github.com/ahmetb/go-linq/union.go
+++ b/vendor/github.com/ahmetb/go-linq/union.go
@@ -2,9 +2,10 @@ package linq
// Union produces the set union of two collections.
//
-// This method excludes duplicates from the return set. This is different
-// behavior to the Concat method, which returns all the elements in the input
-// collection including duplicates.
+// This method excludes duplicates from the return set.
+// This is different behavior to the Concat method,
+// which returns all the elements in the input collection
+// including duplicates.
func (q Query) Union(q2 Query) Query {
return Query{
Iterate: func() Iterator {
diff --git a/vendor/github.com/ahmetb/go-linq/where.go b/vendor/github.com/ahmetb/go-linq/where.go
index 6fd4302..26d0bda 100644
--- a/vendor/github.com/ahmetb/go-linq/where.go
+++ b/vendor/github.com/ahmetb/go-linq/where.go
@@ -19,33 +19,11 @@ func (q Query) Where(predicate func(interface{}) bool) Query {
}
}
-// WhereT is the typed version of Where.
+// WhereIndexed filters a collection of values based on a predicate.
+// Each element's index is used in the logic of the predicate function.
//
-// - predicateFn is of type "func(TSource)bool"
-//
-// NOTE: Where has better performance than WhereT.
-func (q Query) WhereT(predicateFn interface{}) Query {
-
- predicateGenericFunc, err := newGenericFunc(
- "WhereT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
-
- predicateFunc := func(item interface{}) bool {
- return predicateGenericFunc.Call(item).(bool)
- }
-
- return q.Where(predicateFunc)
-}
-
-// WhereIndexed filters a collection of values based on a predicate. Each
-// element's index is used in the logic of the predicate function.
-//
-// The first argument represents the zero-based index of the element within
-// collection. The second argument of predicate represents the element to test.
+// The first argument represents the zero-based index of the element within collection.
+// The second argument of predicate represents the element to test.
func (q Query) WhereIndexed(predicate func(int, interface{}) bool) Query {
return Query{
Iterate: func() Iterator {
@@ -66,24 +44,3 @@ func (q Query) WhereIndexed(predicate func(int, interface{}) bool) Query {
},
}
}
-
-// WhereIndexedT is the typed version of WhereIndexed.
-//
-// - predicateFn is of type "func(int,TSource)bool"
-//
-// NOTE: WhereIndexed has better performance than WhereIndexedT.
-func (q Query) WhereIndexedT(predicateFn interface{}) Query {
- predicateGenericFunc, err := newGenericFunc(
- "WhereIndexedT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
-
- predicateFunc := func(index int, item interface{}) bool {
- return predicateGenericFunc.Call(index, item).(bool)
- }
-
- return q.WhereIndexed(predicateFunc)
-}
diff --git a/vendor/github.com/ahmetb/go-linq/zip.go b/vendor/github.com/ahmetb/go-linq/zip.go
index da3dcd3..1314b9a 100644
--- a/vendor/github.com/ahmetb/go-linq/zip.go
+++ b/vendor/github.com/ahmetb/go-linq/zip.go
@@ -1,17 +1,19 @@
package linq
-// Zip applies a specified function to the corresponding elements of two
-// collections, producing a collection of the results.
+// Zip applies a specified function to the corresponding elements
+// of two collections, producing a collection of the results.
//
// The method steps through the two input collections, applying function
-// resultSelector to corresponding elements of the two collections. The method
-// returns a collection of the values that are returned by resultSelector. If
-// the input collections do not have the same number of elements, the method
-// combines elements until it reaches the end of one of the collections. For
-// example, if one collection has three elements and the other one has four, the
-// result collection has only three elements.
-func (q Query) Zip(q2 Query,
- resultSelector func(interface{}, interface{}) interface{}) Query {
+// resultSelector to corresponding elements of the two collections.
+// The method returns a collection of the values that are returned by resultSelector.
+// If the input collections do not have the same number of elements,
+// the method combines elements until it reaches the end of one of the collections.
+// For example, if one collection has three elements and the other one has four,
+// the result collection has only three elements.
+func (q Query) Zip(
+ q2 Query,
+ resultSelector func(interface{}, interface{}) interface{},
+) Query {
return Query{
Iterate: func() Iterator {
@@ -31,25 +33,3 @@ func (q Query) Zip(q2 Query,
},
}
}
-
-// ZipT is the typed version of Zip.
-//
-// - resultSelectorFn is of type "func(TFirst,TSecond)TResult"
-//
-// NOTE: Zip has better performance than ZipT.
-func (q Query) ZipT(q2 Query,
- resultSelectorFn interface{}) Query {
- resultSelectorGenericFunc, err := newGenericFunc(
- "ZipT", "resultSelectorFn", resultSelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
-
- resultSelectorFunc := func(item1 interface{}, item2 interface{}) interface{} {
- return resultSelectorGenericFunc.Call(item1, item2)
- }
-
- return q.Zip(q2, resultSelectorFunc)
-}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index e549182..103f816 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1,5 +1,5 @@
-# github.com/ahmetalpbalkan/go-linq v2.0.0-rc0+incompatible
-github.com/ahmetalpbalkan/go-linq
+# github.com/ahmetb/go-linq v2.0.0-rc0+incompatible
+github.com/ahmetb/go-linq
# github.com/go-ini/ini v1.57.0
github.com/go-ini/ini
# github.com/json-iterator/go v1.1.10