diff --git a/go.mod b/go.mod
index 65cd910d6..d2950316f 100644
--- a/go.mod
+++ b/go.mod
@@ -3,12 +3,12 @@ module github.com/cloudwego/hertz
go 1.17
require (
- github.com/bytedance/go-tagexpr/v2 v2.9.2
github.com/bytedance/gopkg v0.1.0
github.com/bytedance/mockey v1.2.12
github.com/bytedance/sonic v1.12.0
github.com/cloudwego/netpoll v0.6.4
github.com/fsnotify/fsnotify v1.5.4
+ github.com/nyaruka/phonenumbers v1.0.55
github.com/tidwall/gjson v1.14.4
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.24.0
@@ -21,11 +21,8 @@ require (
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/golang/protobuf v1.5.0 // indirect
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
- github.com/henrylee2cn/ameda v1.4.10 // indirect
- github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 // indirect
github.com/jtolds/gls v4.20.0+incompatible // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
- github.com/nyaruka/phonenumbers v1.0.55 // indirect
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect
github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/tidwall/match v1.1.1 // indirect
diff --git a/go.sum b/go.sum
index 98999c738..7e920d459 100644
--- a/go.sum
+++ b/go.sum
@@ -1,6 +1,3 @@
-github.com/bytedance/go-tagexpr/v2 v2.9.2 h1:QySJaAIQgOEDQBLS3x9BxOWrnhqu5sQ+f6HaZIxD39I=
-github.com/bytedance/go-tagexpr/v2 v2.9.2/go.mod h1:5qsx05dYOiUXOUgnQ7w3Oz8BYs2qtM/bJokdLb79wRM=
-github.com/bytedance/gopkg v0.0.0-20240507064146-197ded923ae3/go.mod h1:FtQG3YbQG9L/91pbKSw787yBQPutC+457AvDW77fgUQ=
github.com/bytedance/gopkg v0.1.0 h1:aAxB7mm1qms4Wz4sp8e1AtKDOeFLtdqvGiUe7aonRJs=
github.com/bytedance/gopkg v0.1.0/go.mod h1:FtQG3YbQG9L/91pbKSw787yBQPutC+457AvDW77fgUQ=
github.com/bytedance/mockey v1.2.12 h1:aeszOmGw8CPX8CRx1DZ/Glzb1yXvhjDh6jdFBNZjsU4=
@@ -14,8 +11,6 @@ github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
-github.com/cloudwego/netpoll v0.6.2 h1:+KdILv5ATJU+222wNNXpHapYaBeRvvL8qhJyhcxRxrQ=
-github.com/cloudwego/netpoll v0.6.2/go.mod h1:kaqvfZ70qd4T2WtIIpCOi5Cxyob8viEpzLhCrTrz3HM=
github.com/cloudwego/netpoll v0.6.4 h1:z/dA4sOTUQof6zZIO4QNnLBXsDFFFEos9OOGloR6kno=
github.com/cloudwego/netpoll v0.6.4/go.mod h1:BtM+GjKTdwKoC8IOzD08/+8eEn2gYoiNLipFca6BVXQ=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -30,11 +25,6 @@ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/henrylee2cn/ameda v1.4.8/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4=
-github.com/henrylee2cn/ameda v1.4.10 h1:JdvI2Ekq7tapdPsuhrc4CaFiqw6QXFvZIULWJgQyCAk=
-github.com/henrylee2cn/ameda v1.4.10/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4=
-github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 h1:yE9ULgp02BhYIrO6sdV/FPe0xQM6fNHkVQW2IAymfM0=
-github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8/go.mod h1:Nhe/DM3671a5udlv2AdV2ni/MZzgfv2qrPL5nIi3EGQ=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
@@ -51,14 +41,11 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
@@ -92,7 +79,6 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/internal/tagexpr/README.md b/internal/tagexpr/README.md
index d3ea44972..b248ac3b4 100644
--- a/internal/tagexpr/README.md
+++ b/internal/tagexpr/README.md
@@ -1,203 +1,3 @@
-# go-tagexpr [![report card](https://goreportcard.com/badge/github.com/bytedance/go-tagexpr?style=flat-square)](http://goreportcard.com/report/bytedance/go-tagexpr) [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](http://godoc.org/github.com/bytedance/go-tagexpr)
+# go-tagexpr
-An interesting go struct tag expression syntax for field validation, etc.
-
-## Usage
-
-- **[Validator](https://github.com/bytedance/go-tagexpr/tree/master/validator)**: A powerful validator that supports struct tag expression
-
-- **[Binding](https://github.com/bytedance/go-tagexpr/tree/master/binding)**: A powerful HTTP request parameters binder that supports struct tag expression
-
-## Feature
-
-- Support for a variety of common operator
-- Support for accessing arrays, slices, members of the dictionary
-- Support access to any field in the current structure
-- Support access to nested fields, non-exported fields, etc.
-- Support variable
-- Support registers function expression
-- Built-in len, sprintf, regexp functions
-- Support single mode and multiple mode to define expression
-- Parameter check subpackage
-- Use offset pointers to directly take values, better performance
-- Required go version ≥1.9
-
-## Example
-
-```go
-package tagexpr_test
-
-import (
- "fmt"
-
- tagexpr "github.com/bytedance/go-tagexpr/v2"
-)
-
-func Example() {
- type T struct {
- A int `tagexpr:"$<0||$>=100"`
- B string `tagexpr:"len($)>1 && regexp('^\\w*$')"`
- C bool `tagexpr:"expr1:(f.g)$>0 && $; expr2:'C must be true when T.f.g>0'"`
- d []string `tagexpr:"@:len($)>0 && $[0]=='D'; msg:sprintf('invalid d: %v',$)"`
- e map[string]int `tagexpr:"len($)==$['len']"`
- e2 map[string]*int `tagexpr:"len($)==$['len']"`
- f struct {
- g int `tagexpr:"$"`
- }
- h int `tagexpr:"$>minVal"`
- }
-
- vm := tagexpr.New("tagexpr")
- t := &T{
- A: 107,
- B: "abc",
- C: true,
- d: []string{"x", "y"},
- e: map[string]int{"len": 1},
- e2: map[string]*int{"len": new(int)},
- f: struct {
- g int `tagexpr:"$"`
- }{1},
- h: 10,
- }
-
- tagExpr, err := vm.Run(t)
- if err != nil {
- panic(err)
- }
-
- fmt.Println(tagExpr.Eval("A"))
- fmt.Println(tagExpr.Eval("B"))
- fmt.Println(tagExpr.Eval("C@expr1"))
- fmt.Println(tagExpr.Eval("C@expr2"))
- if !tagExpr.Eval("d").(bool) {
- fmt.Println(tagExpr.Eval("d@msg"))
- }
- fmt.Println(tagExpr.Eval("e"))
- fmt.Println(tagExpr.Eval("e2"))
- fmt.Println(tagExpr.Eval("f.g"))
- fmt.Println(tagExpr.EvalWithEnv("h", map[string]interface{}{"minVal": 9}))
- fmt.Println(tagExpr.EvalWithEnv("h", map[string]interface{}{"minVal": 11}))
-
- // Output:
- // true
- // true
- // true
- // C must be true when T.f.g>0
- // invalid d: [x y]
- // true
- // false
- // 1
- // true
- // false
-}
-```
-
-## Syntax
-
-Struct tag syntax spec:
-
-```
-type T struct {
- // Single model
- Field1 T1 `tagName:"expression"`
- // Multiple model
- Field2 T2 `tagName:"exprName:expression; [exprName2:expression2;]..."`
- // Omit it
- Field3 T3 `tagName:"-"`
- // Omit it when it is nil
- Field4 T4 `tagName:"?"`
- ...
-}
-```
-
-NOTE: **The `exprName` under the same struct field cannot be the same!**
-
-|Operator or Operand|Explain|
-|-----|---------|
-|`true` `false`|boolean|
-|`0` `0.0`|float64 "0"|
-|`''`|String|
-|`\\'`| Escape `'` delims in string|
-|`\"`| Escape `"` delims in string|
-|`nil`|nil, undefined|
-|`!`|not|
-|`+`|Digital addition or string splicing|
-|`-`|Digital subtraction or negative|
-|`*`|Digital multiplication|
-|`/`|Digital division|
-|`%`|division remainder, as: `float64(int64(a)%int64(b))`|
-|`==`|`eq`|
-|`!=`|`ne`|
-|`>`|`gt`|
-|`>=`|`ge`|
-|`<`|`lt`|
-|`<=`|`le`|
-|`&&`|Logic `and`|
-|`\|\|`|Logic `or`|
-|`()`|Expression group|
-|`(X)$`|Struct field value named X|
-|`(X.Y)$`|Struct field value named X.Y|
-|`$`|Shorthand for `(X)$`, omit `(X)` to indicate current struct field value|
-|`(X)$['A']`|Map value with key A or struct A sub-field in the struct field X|
-|`(X)$[0]`|The 0th element or sub-field of the struct field X(type: map, slice, array, struct)|
-|`len((X)$)`|Built-in function `len`, the length of struct field X|
-|`mblen((X)$)`|the length of string field X (character number)|
-|`regexp('^\\w*$', (X)$)`|Regular match the struct field X, return boolean|
-|`regexp('^\\w*$')`|Regular match the current struct field, return boolean|
-|`sprintf('X value: %v', (X)$)`|`fmt.Sprintf`, format the value of struct field X|
-|`range(KvExpr, forEachExpr)`|Iterate over an array, slice, or dictionary
- `#k` is the element key var
- `#v` is the element value var
- `##` is the number of elements
- e.g. [example](spec_range_test.go)|
-|`in((X)$, enum_1, ...enum_n)`|Check if the first parameter is one of the enumerated parameters|
-
-
-
-
-
-Operator priority(high -> low):
-
-* `()` `!` `bool` `float64` `string` `nil`
-* `*` `/` `%`
-* `+` `-`
-* `<` `<=` `>` `>=`
-* `==` `!=`
-* `&&`
-* `||`
-
-## Field Selector
-
-```
-field_lv1.field_lv2...field_lvn
-```
-
-## Expression Selector
-
-- If expression is **single model** or exprName is `@`:
-
-```
-field_lv1.field_lv2...field_lvn
-```
-
-- If expression is **multiple model** and exprName is not `@`:
-
-```
-field_lv1.field_lv2...field_lvn@exprName
-```
-
-## Benchmark
-
-```
-goos: darwin
-goarch: amd64
-pkg: github.com/bytedance/go-tagexpr
-BenchmarkTagExpr-4 10000000 148 ns/op 32 B/op 3 allocs/op
-BenchmarkReflect-4 10000000 182 ns/op 16 B/op 2 allocs/op
-PASS
-```
-
-[Go to test code](https://github.com/bytedance/go-tagexpr/blob/master/tagexpr_test.go#L9-L56)
+originally from https://github.com/bytedance/go-tagexpr
diff --git a/internal/tagexpr/example_test.go b/internal/tagexpr/example_test.go
index 1a16bc82a..fab5e87a4 100644
--- a/internal/tagexpr/example_test.go
+++ b/internal/tagexpr/example_test.go
@@ -17,7 +17,7 @@ package tagexpr_test
import (
"fmt"
- tagexpr "github.com/bytedance/go-tagexpr/v2"
+ "github.com/cloudwego/hertz/internal/tagexpr"
)
func Example() {
@@ -31,7 +31,7 @@ func Example() {
f struct {
g int `tagexpr:"$"`
}
- h int `tagexpr:"$>minVal"`
+ h int `tagexpr:"$>minVal"`
}
vm := tagexpr.New("tagexpr")
diff --git a/internal/tagexpr/expr.go b/internal/tagexpr/expr.go
index 73765da08..1adb4f87c 100644
--- a/internal/tagexpr/expr.go
+++ b/internal/tagexpr/expr.go
@@ -15,15 +15,12 @@
package tagexpr
import (
- "bytes"
"context"
"fmt"
- "os"
-
- "github.com/andeya/goutil"
)
type variableKeyType string
+
const variableKey variableKeyType = "__ENV_KEY__"
// Expr expression
@@ -297,43 +294,3 @@ func (eb *exprBackground) SetRightOperand(right ExprNode) {
}
func (*exprBackground) Run(context.Context, string, *TagExpr) interface{} { return nil }
-
-var debugSwitch = goutil.IsGoTest()
-
-func printf(format string, a ...interface{}) {
- if debugSwitch {
- fmt.Fprintf(os.Stderr, format, a...)
- }
-}
-
-func printExprNode(node ExprNode) {
- if node == nil {
- return
- }
- tail := true
- if node.Parent() != nil {
- tail = node == node.Parent().RightOperand()
- }
- printf("%s\n\n", formatExprNode(node, 0, tail))
-}
-
-func formatExprNode(node ExprNode, level int, tail bool) []byte {
- var b bytes.Buffer
- if node == nil {
- } else {
- b.Write(formatExprNode(node.LeftOperand(), level+1, false))
-
- b.Write(bytes.Repeat([]byte(" "), level))
- if tail {
- b.Write([]byte("└── "))
- } else {
- b.Write([]byte("┌── "))
- }
-
- b.Write([]byte(node.String()))
- b.Write([]byte("\n"))
-
- b.Write(formatExprNode(node.RightOperand(), level+1, true))
- }
- return b.Bytes()
-}
diff --git a/internal/tagexpr/go.mod b/internal/tagexpr/go.mod
deleted file mode 100644
index 1c2552325..000000000
--- a/internal/tagexpr/go.mod
+++ /dev/null
@@ -1,14 +0,0 @@
-module github.com/bytedance/go-tagexpr/v2
-
-go 1.14
-
-require (
- github.com/andeya/ameda v1.5.3
- github.com/andeya/goutil v1.0.1
- github.com/davecgh/go-spew v1.1.1
- github.com/nyaruka/phonenumbers v1.0.55
- github.com/stretchr/testify v1.7.5
- github.com/tidwall/match v1.1.1
- github.com/tidwall/pretty v1.2.0
- google.golang.org/protobuf v1.27.1
-)
diff --git a/internal/tagexpr/go.sum b/internal/tagexpr/go.sum
deleted file mode 100644
index 79105e431..000000000
--- a/internal/tagexpr/go.sum
+++ /dev/null
@@ -1,35 +0,0 @@
-github.com/andeya/ameda v1.5.3 h1:SvqnhQPZwwabS8HQTRGfJwWPl2w9ZIPInHAw9aE1Wlk=
-github.com/andeya/ameda v1.5.3/go.mod h1:FQDHRe1I995v6GG+8aJ7UIUToEmbdTJn/U26NCPIgXQ=
-github.com/andeya/goutil v1.0.1 h1:eiYwVyAnnK0dXU5FJsNjExkJW4exUGn/xefPt3k4eXg=
-github.com/andeya/goutil v1.0.1/go.mod h1:jEG5/QnnhG7yGxwFUX6Q+JGMif7sjdHmmNVjn7nhJDo=
-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=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/nyaruka/phonenumbers v1.0.55 h1:bj0nTO88Y68KeUQ/n3Lo2KgK7lM1hF7L9NFuwcCl3yg=
-github.com/nyaruka/phonenumbers v1.0.55/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U=
-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/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q=
-github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
-github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
-github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
-github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
-google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-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/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/internal/tagexpr/selector.go b/internal/tagexpr/selector.go
index 044380cca..ba0fe343e 100644
--- a/internal/tagexpr/selector.go
+++ b/internal/tagexpr/selector.go
@@ -18,11 +18,6 @@ const (
// FieldSelector expression selector
type FieldSelector string
-// JoinFieldSelector creates a field selector.
-func JoinFieldSelector(path ...string) string {
- return strings.Join(path, FieldSeparator)
-}
-
// Name returns the current field name.
func (f FieldSelector) Name() string {
s := string(f)
@@ -59,15 +54,6 @@ func (f FieldSelector) String() string {
return string(f)
}
-// JoinExprSelector creates a expression selector.
-func JoinExprSelector(pathFields []string, exprName string) string {
- p := strings.Join(pathFields, FieldSeparator)
- if p == "" || exprName == "" {
- return p
- }
- return p + ExprNameSeparator + exprName
-}
-
// ExprSelector expression selector
type ExprSelector string
diff --git a/internal/tagexpr/selector_test.go b/internal/tagexpr/selector_test.go
index 393383253..586e4c7e4 100644
--- a/internal/tagexpr/selector_test.go
+++ b/internal/tagexpr/selector_test.go
@@ -2,13 +2,15 @@ package tagexpr
import (
"testing"
-
- "github.com/stretchr/testify/assert"
)
func TestExprSelector(t *testing.T) {
es := ExprSelector("F1.Index")
field, ok := es.ParentField()
- assert.True(t, ok)
- assert.Equal(t, "F1", field)
+ if !ok {
+ t.Fatal("not ok")
+ }
+ if "F1" != field {
+ t.Fatal(field)
+ }
}
diff --git a/internal/tagexpr/spec_func.go b/internal/tagexpr/spec_func.go
index 610fc8841..0b2a9ca23 100644
--- a/internal/tagexpr/spec_func.go
+++ b/internal/tagexpr/spec_func.go
@@ -20,8 +20,6 @@ import (
"reflect"
"regexp"
"strings"
-
- "github.com/andeya/goutil/errors"
)
// --------------------------- Custom function ---------------------------
@@ -54,7 +52,7 @@ func RegFunc(funcName string, fn func(...interface{}) interface{}, force ...bool
if len(force) == 0 || !force[0] {
_, ok := funcList[funcName]
if ok {
- return errors.Errorf("duplicate registration expression function: %s", funcName)
+ return fmt.Errorf("duplicate registration expression function: %s", funcName)
}
}
funcList[funcName] = newFunc(funcName, fn)
diff --git a/internal/tagexpr/spec_func_test.go b/internal/tagexpr/spec_func_test.go
index d6872f251..e353b7d96 100644
--- a/internal/tagexpr/spec_func_test.go
+++ b/internal/tagexpr/spec_func_test.go
@@ -15,11 +15,11 @@
package tagexpr_test
import (
+ "reflect"
"regexp"
"testing"
- "github.com/bytedance/go-tagexpr/v2"
- "github.com/stretchr/testify/assert"
+ "github.com/cloudwego/hertz/internal/tagexpr"
)
func TestFunc(t *testing.T) {
@@ -96,5 +96,9 @@ func TestRangeIn(t *testing.T) {
F: a,
// F: b,
})
- assert.Equal(t, []interface{}{true, true, true}, r.Eval("F"))
+ expect := []interface{}{true, true, true}
+ actual := r.Eval("F")
+ if !reflect.DeepEqual(expect, actual) {
+ t.Fatal("not equal", expect, actual)
+ }
}
diff --git a/internal/tagexpr/spec_operand.go b/internal/tagexpr/spec_operand.go
index b18e6ce7f..8ae356a68 100644
--- a/internal/tagexpr/spec_operand.go
+++ b/internal/tagexpr/spec_operand.go
@@ -21,8 +21,6 @@ import (
"regexp"
"strconv"
"strings"
-
- "github.com/andeya/ameda"
)
// --------------------------- Operand ---------------------------
@@ -214,7 +212,6 @@ func readVariableExprNode(expr *string) ExprNode {
}
}
-
func getBoolAndSignOpposite(expr *string) (last string, boolOpposite *bool, signOpposite *bool) {
last = strings.TrimLeft(last, "+")
last, boolOpposite = getOpposite(expr, "!")
@@ -241,7 +238,7 @@ func toString(i interface{}, enforce bool) (string, bool) {
case nil:
return "", false
default:
- rv := ameda.DereferenceValue(reflect.ValueOf(i))
+ rv := dereferenceValue(reflect.ValueOf(i))
if rv.Kind() == reflect.String {
return rv.String(), true
}
@@ -287,7 +284,7 @@ func toFloat64(i interface{}, tryParse bool) (float64, bool) {
case nil:
ok = false
default:
- rv := ameda.DereferenceValue(reflect.ValueOf(t))
+ rv := dereferenceValue(reflect.ValueOf(t))
switch rv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v = float64(rv.Int())
@@ -346,7 +343,7 @@ func realValue(v interface{}, boolOpposite *bool, signOpposite *bool) interface{
t[k] = realValue(v, boolOpposite, signOpposite)
}
default:
- rv := ameda.DereferenceValue(reflect.ValueOf(v))
+ rv := dereferenceValue(reflect.ValueOf(v))
switch rv.Kind() {
case reflect.String:
v = rv.String()
diff --git a/internal/tagexpr/spec_range_test.go b/internal/tagexpr/spec_range_test.go
index 3e209df79..071254415 100644
--- a/internal/tagexpr/spec_range_test.go
+++ b/internal/tagexpr/spec_range_test.go
@@ -1,10 +1,10 @@
package tagexpr_test
import (
+ "reflect"
"testing"
- "github.com/bytedance/go-tagexpr/v2"
- "github.com/stretchr/testify/assert"
+ "github.com/cloudwego/hertz/internal/tagexpr"
)
func TestIssue12(t *testing.T) {
@@ -25,10 +25,16 @@ func TestIssue12(t *testing.T) {
MFs: []map[string][]I{{"m": a}},
MFs2: []map[string][]I{},
})
- assert.Equal(t, []interface{}{">0:6", ">1:7"}, r.Eval("F"))
- assert.Equal(t, []interface{}{[]interface{}{">0:6", ">1:7"}}, r.Eval("Fs"))
- assert.Equal(t, []interface{}{">m0:6", ">m1:7"}, r.Eval("M"))
- assert.Equal(t, []interface{}{[]interface{}{[]interface{}{">0:6", ">1:7"}}}, r.Eval("MFs"))
- assert.Equal(t, []interface{}{}, r.Eval("MFs2"))
- assert.Equal(t, true, r.EvalBool("MFs2"))
+ assertEqual(t, []interface{}{">0:6", ">1:7"}, r.Eval("F"))
+ assertEqual(t, []interface{}{[]interface{}{">0:6", ">1:7"}}, r.Eval("Fs"))
+ assertEqual(t, []interface{}{[]interface{}{[]interface{}{">0:6", ">1:7"}}}, r.Eval("MFs"))
+ assertEqual(t, []interface{}{}, r.Eval("MFs2"))
+ assertEqual(t, true, r.EvalBool("MFs2"))
+
+ // result may not stable for map
+ got := r.Eval("M")
+ if !reflect.DeepEqual([]interface{}{">m0:6", ">m1:7"}, got) &&
+ !reflect.DeepEqual([]interface{}{">m1:7", ">m0:6"}, got) {
+ t.Fatal(got)
+ }
}
diff --git a/internal/tagexpr/tagexpr.go b/internal/tagexpr/tagexpr.go
index 288f3510b..dc98aff50 100644
--- a/internal/tagexpr/tagexpr.go
+++ b/internal/tagexpr/tagexpr.go
@@ -23,8 +23,6 @@ import (
"strings"
"sync"
"unsafe"
-
- "github.com/andeya/ameda"
)
// Internally unified data types
@@ -115,21 +113,20 @@ func (vm *VM) Run(structPtrOrReflectValue interface{}) (*TagExpr, error) {
var v reflect.Value
switch t := structPtrOrReflectValue.(type) {
case reflect.Value:
- v = ameda.DereferenceValue(t)
+ v = dereferenceValue(t)
default:
- v = ameda.DereferenceValue(reflect.ValueOf(t))
+ v = dereferenceValue(reflect.ValueOf(t))
}
if err := checkStructMapAddr(v); err != nil {
return nil, err
}
- u := ameda.ValueFrom2(&v)
- ptr := unsafe.Pointer(u.Pointer())
+ ptr := rvPtr(v)
if ptr == nil {
return nil, unsupportNil
}
- tid := u.RuntimeTypeID()
+ tid := rvType(v)
var err error
vm.rw.RLock()
s, ok := vm.structJar[tid]
@@ -175,12 +172,12 @@ func checkStructMapAddr(v reflect.Value) error {
}
func (vm *VM) subRunAll(omitNil bool, tePath string, value reflect.Value, fn func(*TagExpr, error) error) error {
- rv := ameda.DereferenceInterfaceValue(value)
+ rv := dereferenceInterfaceValue(value)
if !rv.IsValid() {
return nil
}
- rt := ameda.DereferenceType(rv.Type())
- rv = ameda.DereferenceValue(rv)
+ rt := dereferenceType(rv.Type())
+ rv = dereferenceValue(rv)
switch rt.Kind() {
case reflect.Struct:
if len(tePath) == 0 {
@@ -188,22 +185,21 @@ func (vm *VM) subRunAll(omitNil bool, tePath string, value reflect.Value, fn fun
return err
}
}
- u := ameda.ValueFrom2(&rv)
- ptr := unsafe.Pointer(u.Pointer())
+ ptr := rvPtr(rv)
if ptr == nil {
if omitNil {
return nil
}
return fn(nil, unsupportNil)
}
- return fn(vm.subRun(tePath, rt, u.RuntimeTypeID(), ptr))
+ return fn(vm.subRun(tePath, rt, rvType(rv), ptr))
case reflect.Slice, reflect.Array:
count := rv.Len()
if count == 0 {
return nil
}
- switch ameda.DereferenceType(rv.Type().Elem()).Kind() {
+ switch dereferenceType(rv.Type().Elem()).Kind() {
case reflect.Struct, reflect.Interface, reflect.Slice, reflect.Array, reflect.Map:
for i := count - 1; i >= 0; i-- {
err := vm.subRunAll(omitNil, tePath+"["+strconv.Itoa(i)+"]", rv.Index(i), fn)
@@ -221,11 +217,11 @@ func (vm *VM) subRunAll(omitNil bool, tePath string, value reflect.Value, fn fun
}
var canKey, canValue bool
rt := rv.Type()
- switch ameda.DereferenceType(rt.Key()).Kind() {
+ switch dereferenceType(rt.Key()).Kind() {
case reflect.Struct, reflect.Interface, reflect.Slice, reflect.Array, reflect.Map:
canKey = true
}
- switch ameda.DereferenceType(rt.Elem()).Kind() {
+ switch dereferenceType(rt.Elem()).Kind() {
case reflect.Struct, reflect.Interface, reflect.Slice, reflect.Array, reflect.Map:
canValue = true
}
@@ -278,7 +274,7 @@ func (vm *VM) registerStructLocked(structType reflect.Type) (*structVM, error) {
if err != nil {
return nil, err
}
- tid := ameda.RuntimeTypeID(structType)
+ tid := rtType(structType)
s, had := vm.structJar[tid]
if had {
return s, s.err
@@ -813,7 +809,7 @@ func FakeBool(v interface{}) bool {
}
return bol
default:
- vv := ameda.DereferenceValue(reflect.ValueOf(v))
+ vv := dereferenceValue(reflect.ValueOf(v))
if vv.IsValid() || vv.IsZero() {
return false
}
@@ -877,7 +873,7 @@ func (t *TagExpr) Eval(exprSelector string) interface{} {
//
// format: fieldName, fieldName.exprName, fieldName1.fieldName2.exprName1
// result types: float64, string, bool, nil
-func (t *TagExpr) EvalWithEnv(exprSelector string, env map[string]interface{})interface{} {
+func (t *TagExpr) EvalWithEnv(exprSelector string, env map[string]interface{}) interface{} {
expr, ok := t.s.exprs[exprSelector]
if !ok {
// Compatible with single mode or the expression with the name @
@@ -940,7 +936,7 @@ func (t *TagExpr) Range(fn func(*ExprHandler) error) error {
keyPath := f.fieldSelector + "{k}"
for _, key := range v.MapKeys() {
if mapKeyStructVM != nil {
- p := unsafe.Pointer(ameda.ValueFrom(derefValue(key)).Pointer())
+ p := rvPtr(derefValue(key))
if omitNil && p == nil {
continue
}
@@ -955,7 +951,7 @@ func (t *TagExpr) Range(fn func(*ExprHandler) error) error {
}
}
if mapOrSliceElemStructVM != nil {
- p := unsafe.Pointer(ameda.ValueFrom(derefValue(v.MapIndex(key))).Pointer())
+ p := rvPtr(derefValue(v.MapIndex(key)))
if omitNil && p == nil {
continue
}
@@ -975,7 +971,7 @@ func (t *TagExpr) Range(fn func(*ExprHandler) error) error {
// slice or array
for i := v.Len() - 1; i >= 0; i-- {
if mapOrSliceElemStructVM != nil {
- p := unsafe.Pointer(ameda.ValueFrom(derefValue(v.Index(i))).Pointer())
+ p := rvPtr(derefValue(v.Index(i)))
if omitNil && p == nil {
continue
}
diff --git a/internal/tagexpr/tagexpr_test.go b/internal/tagexpr/tagexpr_test.go
index 4c316f763..1eb8abf5a 100644
--- a/internal/tagexpr/tagexpr_test.go
+++ b/internal/tagexpr/tagexpr_test.go
@@ -12,22 +12,31 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package tagexpr
+package tagexpr_test
import (
+ "fmt"
"reflect"
"strconv"
"testing"
"time"
- "github.com/stretchr/testify/assert"
+ "github.com/cloudwego/hertz/internal/tagexpr"
)
+func assertEqual(t *testing.T, v1, v2 interface{}, msgs ...interface{}) {
+ t.Helper()
+ if reflect.DeepEqual(v1, v2) {
+ return
+ }
+ t.Fatal(fmt.Sprintf("not equal %v %v", v1, v2) + "\n" + fmt.Sprint(msgs...))
+}
+
func BenchmarkTagExpr(b *testing.B) {
type T struct {
a int `bench:"$%3"`
}
- vm := New("bench")
+ vm := tagexpr.New("bench")
vm.MustRun(new(T)) // warm up
b.ReportAllocs()
b.ResetTimer()
@@ -214,7 +223,7 @@ func Test(t *testing.T) {
},
}
for i, c := range cases {
- vm := New(c.tagName)
+ vm := tagexpr.New(c.tagName)
// vm.WarmUp(c.structure)
tagExpr, err := vm.Run(c.structure)
if err != nil {
@@ -226,7 +235,7 @@ func Test(t *testing.T) {
t.Fatalf("Eval Serial: %d, selector: %q, got: %v, expect: %v", i, selector, val, value)
}
}
- tagExpr.Range(func(eh *ExprHandler) error {
+ tagExpr.Range(func(eh *tagexpr.ExprHandler) error {
es := eh.ExprSelector()
t.Logf("Range selector: %s, field: %q exprName: %q", es, es.Field(), es.Name())
value := c.tests[es.String()]
@@ -283,7 +292,7 @@ func TestFieldNotInit(t *testing.T) {
g: &g,
i: "12",
}
- vm := New("expr")
+ vm := tagexpr.New("expr")
e, err := vm.Run(structure)
if err != nil {
t.Fatal(err)
@@ -315,15 +324,17 @@ func TestFieldNotInit(t *testing.T) {
for _, c := range cases {
fh, _ := e.Field(c.fieldSelector)
val := fh.Value(false).Interface()
- assert.Equal(t, c.value, val, c.fieldSelector)
+ assertEqual(t, c.value, val, c.fieldSelector)
}
var i int
- e.RangeFields(func(fh *FieldHandler) bool {
+ e.RangeFields(func(fh *tagexpr.FieldHandler) bool {
val := fh.Value(false).Interface()
if fh.StringSelector() == "c.d" {
- assert.NotNil(t, fh.EvalFuncs()["c.d@test"])
+ if fh.EvalFuncs()["c.d@test"] == nil {
+ t.Fatal("nil")
+ }
}
- assert.Equal(t, cases[i].value, val, fh.StringSelector())
+ assertEqual(t, cases[i].value, val, fh.StringSelector())
i++
return true
})
@@ -392,7 +403,7 @@ func TestFieldInitZero(t *testing.T) {
i: "12",
}
- vm := New("")
+ vm := tagexpr.New("")
e, err := vm.Run(structure)
if err != nil {
t.Fatal(err)
@@ -429,7 +440,7 @@ func TestFieldInitZero(t *testing.T) {
for _, c := range cases {
fh, _ := e.Field(c.fieldSelector)
val := fh.Value(true).Interface()
- assert.Equal(t, c.value, val, c.fieldSelector)
+ assertEqual(t, c.value, val, c.fieldSelector)
}
}
@@ -531,7 +542,7 @@ func TestOperator(t *testing.T) {
}
for i, c := range cases {
- vm := New(c.tagName)
+ vm := tagexpr.New(c.tagName)
// vm.WarmUp(c.structure)
tagExpr, err := vm.Run(c.structure)
if err != nil {
@@ -543,7 +554,7 @@ func TestOperator(t *testing.T) {
t.Fatalf("Eval NO: %d, selector: %q, got: %v, expect: %v", i, selector, val, value)
}
}
- tagExpr.Range(func(eh *ExprHandler) error {
+ tagExpr.Range(func(eh *tagexpr.ExprHandler) error {
es := eh.ExprSelector()
t.Logf("Range selector: %s, field: %q exprName: %q", es, es.Field(), es.Name())
value := c.tests[es.String()]
@@ -571,13 +582,13 @@ func TestStruct(t *testing.T) {
}
a := new(A)
a.B.C.D.X = "xxx"
- vm := New("vd")
+ vm := tagexpr.New("vd")
expr := vm.MustRun(a)
- assert.Equal(t, "xxx", expr.EvalString("B.C2"))
- assert.Equal(t, "xxx", expr.EvalString("B.C3"))
- assert.Equal(t, "xxx", expr.EvalString("B.C"))
- assert.Equal(t, "xxx", expr.EvalString("B.C.D.X"))
- expr.Range(func(eh *ExprHandler) error {
+ assertEqual(t, "xxx", expr.EvalString("B.C2"))
+ assertEqual(t, "xxx", expr.EvalString("B.C3"))
+ assertEqual(t, "xxx", expr.EvalString("B.C"))
+ assertEqual(t, "xxx", expr.EvalString("B.C.D.X"))
+ expr.Range(func(eh *tagexpr.ExprHandler) error {
es := eh.ExprSelector()
t.Logf("Range selector: %s, field: %q exprName: %q", es, es.Field(), es.Name())
if eh.Eval().(string) != "xxx" {
@@ -601,7 +612,7 @@ func TestStruct2(t *testing.T) {
b := new(IframeBlock)
b.XBlock.BlockType = "BlockType"
b.Props.Data.DataType = "DataType"
- vm := New("vd")
+ vm := tagexpr.New("vd")
expr := vm.MustRun(b)
if expr.EvalString("XBlock.BlockType") != "BlockType" {
t.Fatal(expr.EvalString("XBlock.BlockType"))
@@ -667,17 +678,19 @@ func TestStruct3(t *testing.T) {
9: p2,
}
- vm := New("vd")
+ vm := tagexpr.New("vd")
expr := vm.MustRun(b)
if expr.EvalString("XBlock.BlockType") != "BlockType" {
t.Fatal(expr.EvalString("XBlock.BlockType"))
}
- err := expr.Range(func(eh *ExprHandler) error {
+ err := expr.Range(func(eh *tagexpr.ExprHandler) error {
es := eh.ExprSelector()
t.Logf("Range selector: %s, field: %q exprName: %q, eval: %v", eh.Path(), es.Field(), es.Name(), eh.Eval())
return nil
})
- assert.NoError(t, err)
+ if err != nil {
+ t.Fatal(err)
+ }
}
func TestNilField(t *testing.T) {
@@ -687,11 +700,13 @@ func TestNilField(t *testing.T) {
} `tagexpr:"$"`
Y **struct{} `tagexpr:"$"`
}
- vm := New("tagexpr")
+ vm := tagexpr.New("tagexpr")
te := vm.MustRun(&P{})
- te.Range(func(eh *ExprHandler) error {
+ te.Range(func(eh *tagexpr.ExprHandler) error {
r := eh.Eval()
- assert.Nil(t, r, eh.Path())
+ if r != nil {
+ t.Fatal(eh.Path())
+ }
return nil
})
@@ -703,10 +718,11 @@ func TestNilField(t *testing.T) {
// Nil1: new(int),
Nil2: new(int),
}
- vm.MustRun(g).Range(func(eh *ExprHandler) error {
+ vm.MustRun(g).Range(func(eh *tagexpr.ExprHandler) error {
r, ok := eh.Eval().(bool)
- assert.True(t, ok, eh.Path())
- assert.True(t, r, eh.Path())
+ if !ok || !r {
+ t.Fatal(eh.Path())
+ }
return nil
})
return
@@ -737,14 +753,16 @@ func TestNilField(t *testing.T) {
SI: []interface{}{&M{X: "nn"}},
}
var cnt int
- vm.MustRun(n).Range(func(eh *ExprHandler) error {
+ vm.MustRun(n).Range(func(eh *tagexpr.ExprHandler) error {
r := eh.EvalBool()
- assert.True(t, r, eh.Path())
+ if !r {
+ t.Fatal(eh.Path())
+ }
t.Log("path:", eh.Path(), "es:", eh.ExprSelector(), "val:", r)
cnt++
return nil
})
- assert.Equal(t, 3, cnt)
+ assertEqual(t, 3, cnt)
}
func TestDeepNested(t *testing.T) {
@@ -780,15 +798,15 @@ func TestDeepNested(t *testing.T) {
expectKey := [...]interface{}{"S1.S.I.Address@name", "S2.S.I.Address@name", "S1.S.A[0].Address@name", "S2.S.A[0].Address@name", "S1.S.X[0].Address@name"}
expectValue := [...]interface{}{"I:address", nil, "A:address", nil, "X:address"}
var i int
- vm := New("tagexpr")
- vm.MustRun(data).Range(func(eh *ExprHandler) error {
- assert.Equal(t, expectKey[i], eh.Path())
- assert.Equal(t, expectValue[i], eh.Eval())
+ vm := tagexpr.New("tagexpr")
+ vm.MustRun(data).Range(func(eh *tagexpr.ExprHandler) error {
+ assertEqual(t, expectKey[i], eh.Path())
+ assertEqual(t, expectValue[i], eh.Eval())
i++
t.Log(eh.Path(), eh.ExprSelector(), eh.Eval())
return nil
})
- assert.Equal(t, 5, i)
+ assertEqual(t, 5, i)
}
func TestIssue3(t *testing.T) {
@@ -808,21 +826,23 @@ func TestIssue3(t *testing.T) {
P: new(int),
},
}
- vm := New("vd")
- err := vm.MustRun(a).Range(func(eh *ExprHandler) error {
+ vm := tagexpr.New("vd")
+ err := vm.MustRun(a).Range(func(eh *tagexpr.ExprHandler) error {
switch eh.Path() {
case "F1.Index":
- assert.Equal(t, float64(1), eh.Eval(), eh.Path())
+ assertEqual(t, float64(1), eh.Eval(), eh.Path())
case "F2.Index":
- assert.Equal(t, nil, eh.Eval(), eh.Path())
+ assertEqual(t, nil, eh.Eval(), eh.Path())
case "F1.P":
- assert.Equal(t, true, eh.Eval(), eh.Path())
+ assertEqual(t, true, eh.Eval(), eh.Path())
case "F2.P":
- assert.Equal(t, false, eh.Eval(), eh.Path())
+ assertEqual(t, false, eh.Eval(), eh.Path())
}
return nil
})
- assert.NoError(t, err)
+ if err != nil {
+ t.Fatal(err)
+ }
}
func TestIssue4(t *testing.T) {
@@ -836,12 +856,14 @@ func TestIssue4(t *testing.T) {
B: new(string),
C: &c,
}
- vm := New("te")
- err := vm.MustRun(v).Range(func(eh *ExprHandler) error {
+ vm := tagexpr.New("te")
+ err := vm.MustRun(v).Range(func(eh *tagexpr.ExprHandler) error {
t.Logf("eval:%v, path:%s", eh.EvalFloat(), eh.Path())
return nil
})
- assert.NoError(t, err)
+ if err != nil {
+ t.Fatal(err)
+ }
}
func TestIssue5(t *testing.T) {
@@ -855,17 +877,19 @@ func TestIssue5(t *testing.T) {
F2: 1500,
F3: 1500,
}
- vm := New("vd")
- err := vm.MustRun(a).Range(func(eh *ExprHandler) error {
+ vm := tagexpr.New("vd")
+ err := vm.MustRun(a).Range(func(eh *tagexpr.ExprHandler) error {
switch eh.Path() {
case "F1":
- assert.Equal(t, true, eh.Eval(), eh.Path())
+ assertEqual(t, true, eh.Eval(), eh.Path())
case "F2":
- assert.Equal(t, true, eh.Eval(), eh.Path())
+ assertEqual(t, true, eh.Eval(), eh.Path())
case "F3":
- assert.Equal(t, true, eh.Eval(), eh.Path())
+ assertEqual(t, true, eh.Eval(), eh.Path())
}
return nil
})
- assert.NoError(t, err)
+ if err != nil {
+ t.Fatal(err)
+ }
}
diff --git a/internal/tagexpr/tagparser_test.go b/internal/tagexpr/tagparser_test.go
index aa7f4cc55..fbd382229 100644
--- a/internal/tagexpr/tagparser_test.go
+++ b/internal/tagexpr/tagparser_test.go
@@ -3,8 +3,6 @@ package tagexpr
import (
"reflect"
"testing"
-
- "github.com/stretchr/testify/assert"
)
func TestTagparser(t *testing.T) {
@@ -68,9 +66,11 @@ func TestTagparser(t *testing.T) {
for _, c := range cases {
r, e := parseTag(c.tag.Get("tagexpr"))
if e != nil == c.fail {
- assert.Equal(t, c.expect, r, c.tag)
+ if !reflect.DeepEqual(c.expect, r) {
+ t.Fatal(c.expect, r, c.tag)
+ }
} else {
- assert.Failf(t, string(c.tag), "kvs:%v, err:%v", r, e)
+ t.Fatalf("tag:%s kvs:%v, err:%v", c.tag, r, e)
}
if e != nil {
t.Logf("tag:%q, errMsg:%v", c.tag, e)
diff --git a/internal/tagexpr/utils.go b/internal/tagexpr/utils.go
new file mode 100644
index 000000000..0685d545b
--- /dev/null
+++ b/internal/tagexpr/utils.go
@@ -0,0 +1,85 @@
+package tagexpr
+
+import (
+ "reflect"
+ "unsafe"
+)
+
+func init() {
+ testhack()
+}
+
+func dereferenceValue(v reflect.Value) reflect.Value {
+ for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
+ v = v.Elem()
+ }
+ return v
+}
+
+func dereferenceType(t reflect.Type) reflect.Type {
+ for t.Kind() == reflect.Ptr {
+ t = t.Elem()
+ }
+ return t
+}
+
+func dereferenceInterfaceValue(v reflect.Value) reflect.Value {
+ for v.Kind() == reflect.Interface {
+ v = v.Elem()
+ }
+ return v
+}
+
+type rvtype struct { // reflect.Value
+ abiType uintptr
+ ptr unsafe.Pointer // data pointer
+}
+
+func rvPtr(rv reflect.Value) unsafe.Pointer {
+ return (*rvtype)(unsafe.Pointer(&rv)).ptr
+}
+
+func rvType(rv reflect.Value) uintptr {
+ return (*rvtype)(unsafe.Pointer(&rv)).abiType
+}
+
+func rtType(rt reflect.Type) uintptr {
+ type iface struct {
+ tab uintptr
+ data uintptr
+ }
+ return (*iface)(unsafe.Pointer(&rt)).data
+}
+
+// quick test make sure the hack above works
+func testhack() {
+ type T1 struct {
+ a int
+ }
+ type T2 struct {
+ a int
+ }
+ p0 := &T1{}
+ p1 := &T1{}
+ p2 := &T2{}
+
+ if rvPtr(reflect.ValueOf(p0)) != unsafe.Pointer(p0) ||
+ rvPtr(reflect.ValueOf(p0).Elem()) != unsafe.Pointer(p0) ||
+ rvPtr(reflect.ValueOf(p0)) == rvPtr(reflect.ValueOf(p1)) {
+ panic("rvPtr() compatibility issue found")
+ }
+
+ if rvType(reflect.ValueOf(p0)) != rvType(reflect.ValueOf(p1)) ||
+ rvType(reflect.ValueOf(p0)) == rvType(reflect.ValueOf(p2)) ||
+ rvType(reflect.ValueOf(p0).Elem()) != rvType(reflect.ValueOf(p1).Elem()) ||
+ rvType(reflect.ValueOf(p0).Elem()) == rvType(reflect.ValueOf(p2).Elem()) {
+ panic("rvType() compatibility issue found")
+ }
+
+ if rtType(reflect.TypeOf(p0)) != rtType(reflect.TypeOf(p1)) ||
+ rtType(reflect.TypeOf(p0)) == rtType(reflect.TypeOf(p2)) ||
+ rtType(reflect.TypeOf(p0).Elem()) != rtType(reflect.TypeOf(p1).Elem()) ||
+ rtType(reflect.TypeOf(p0).Elem()) == rtType(reflect.TypeOf(p2).Elem()) {
+ panic("rtType() compatibility issue found")
+ }
+}
diff --git a/internal/tagexpr/validator/example_test.go b/internal/tagexpr/validator/example_test.go
index 9318566dc..da999ca1b 100644
--- a/internal/tagexpr/validator/example_test.go
+++ b/internal/tagexpr/validator/example_test.go
@@ -3,7 +3,7 @@ package validator_test
import (
"fmt"
- vd "github.com/bytedance/go-tagexpr/v2/validator"
+ vd "github.com/cloudwego/hertz/internal/tagexpr/validator"
)
func Example() {
diff --git a/internal/tagexpr/validator/func.go b/internal/tagexpr/validator/func.go
index fedcd36ed..fe965610b 100644
--- a/internal/tagexpr/validator/func.go
+++ b/internal/tagexpr/validator/func.go
@@ -6,7 +6,7 @@ import (
"github.com/nyaruka/phonenumbers"
- "github.com/bytedance/go-tagexpr/v2"
+ "github.com/cloudwego/hertz/internal/tagexpr"
)
// ErrInvalidWithoutMsg verification error without error message.
diff --git a/internal/tagexpr/validator/validator.go b/internal/tagexpr/validator/validator.go
index 577bffc3a..5adc19d24 100644
--- a/internal/tagexpr/validator/validator.go
+++ b/internal/tagexpr/validator/validator.go
@@ -6,7 +6,7 @@
// 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
+// 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,
@@ -22,7 +22,7 @@ import (
"strings"
_ "unsafe"
- tagexpr "github.com/bytedance/go-tagexpr/v2"
+ "github.com/cloudwego/hertz/internal/tagexpr"
)
const (
@@ -55,7 +55,8 @@ func (v *Validator) VM() *tagexpr.VM {
// Validate validates whether the fields of value is valid.
// NOTE:
-// If checkAll=true, validate all the error.
+//
+// If checkAll=true, validate all the error.
func (v *Validator) Validate(value interface{}, checkAll ...bool) error {
var all bool
if len(checkAll) > 0 {
@@ -130,7 +131,8 @@ func (v *Validator) Validate(value interface{}, checkAll ...bool) error {
// SetErrorFactory customizes the factory of validation error.
// NOTE:
-// If errFactory==nil, the default is used
+//
+// If errFactory==nil, the default is used
func (v *Validator) SetErrorFactory(errFactory func(failPath, msg string) error) *Validator {
if errFactory == nil {
errFactory = defaultErrorFactory
diff --git a/internal/tagexpr/validator/validator_test.go b/internal/tagexpr/validator/validator_test.go
index ef1bbec74..1c1fd3647 100644
--- a/internal/tagexpr/validator/validator_test.go
+++ b/internal/tagexpr/validator/validator_test.go
@@ -5,18 +5,30 @@ import (
"errors"
"testing"
- "github.com/stretchr/testify/assert"
-
- vd "github.com/bytedance/go-tagexpr/v2/validator"
+ vd "github.com/cloudwego/hertz/internal/tagexpr/validator"
)
+func assertEqualError(t *testing.T, err error, s string) {
+ t.Helper()
+ if err.Error() != s {
+ t.Fatal("not equal", err, s)
+ }
+}
+
+func assertNoError(t *testing.T, err error) {
+ t.Helper()
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
func TestNil(t *testing.T) {
type F struct {
f struct {
g int `vd:"$%3==1"`
}
}
- assert.EqualError(t, vd.Validate((*F)(nil)), "unsupport data: nil")
+ assertEqualError(t, vd.Validate((*F)(nil)), "unsupport data: nil")
}
func TestAll(t *testing.T) {
@@ -26,7 +38,7 @@ func TestAll(t *testing.T) {
g int `vd:"$%3==1"`
}
}
- assert.EqualError(t, vd.Validate(new(T), true), "email format is incorrect\tinvalid parameter: f.g")
+ assertEqualError(t, vd.Validate(new(T), true), "email format is incorrect\tinvalid parameter: f.g")
}
func TestIssue1(t *testing.T) {
@@ -68,7 +80,7 @@ func TestIssue1(t *testing.T) {
},
},
}
- assert.EqualError(t, vd.Validate(req, false), "email format is incorrect")
+ assertEqualError(t, vd.Validate(req, false), "email format is incorrect")
}
func TestIssue2(t *testing.T) {
@@ -82,7 +94,7 @@ func TestIssue2(t *testing.T) {
},
}
v := vd.New("vd")
- assert.NoError(t, v.Validate(A))
+ assertNoError(t, v.Validate(A))
}
func TestIssue3(t *testing.T) {
@@ -101,7 +113,7 @@ func TestIssue3(t *testing.T) {
},
}
v := vd.New("vd")
- assert.NoError(t, v.Validate(a))
+ assertNoError(t, v.Validate(a))
}
func TestIssue4(t *testing.T) {
@@ -118,23 +130,23 @@ func TestIssue4(t *testing.T) {
v := vd.New("vd")
a := &A{}
- assert.NoError(t, v.Validate(a))
+ assertNoError(t, v.Validate(a))
a = &A{F1: new(C)}
- assert.EqualError(t, v.Validate(a), "index is nil")
+ assertEqualError(t, v.Validate(a), "index is nil")
a = &A{F2: map[string]*C{"x": &C{Index: new(int32)}}}
- assert.EqualError(t, v.Validate(a), "invalid parameter: F2{v for k=x}.Index2")
+ assertEqualError(t, v.Validate(a), "invalid parameter: F2{v for k=x}.Index2")
a = &A{F3: []*C{{Index: new(int32)}}}
- assert.EqualError(t, v.Validate(a), "invalid parameter: F3[0].Index2")
+ assertEqualError(t, v.Validate(a), "invalid parameter: F3[0].Index2")
type B struct {
F1 *C `vd:"$!=nil"`
F2 *C
}
b := &B{}
- assert.EqualError(t, v.Validate(b), "invalid parameter: F1")
+ assertEqualError(t, v.Validate(b), "invalid parameter: F1")
type D struct {
F1 *C
@@ -146,7 +158,7 @@ func TestIssue4(t *testing.T) {
}
b.F1 = new(C)
e := &E{D: []*D{nil}}
- assert.NoError(t, v.Validate(e))
+ assertNoError(t, v.Validate(e))
}
func TestIssue5(t *testing.T) {
@@ -165,11 +177,15 @@ func TestIssue5(t *testing.T) {
b := `{"requests": [{}]}`
var data BatchUpdateSheetRequestArg
err := json.Unmarshal([]byte(b), &data)
- assert.NoError(t, err)
- assert.Equal(t, 1, len(data.Requests))
- assert.Nil(t, data.Requests[0].CopySheet)
+ assertNoError(t, err)
+ if len(data.Requests) != 1 {
+ t.Fatal(len(data.Requests))
+ }
+ if data.Requests[0].CopySheet != nil {
+ t.Fatal(data.Requests[0].CopySheet)
+ }
v := vd.New("vd")
- assert.NoError(t, v.Validate(&data))
+ assertNoError(t, v.Validate(&data))
}
func TestIn(t *testing.T) {
@@ -183,27 +199,27 @@ func TestIn(t *testing.T) {
v := vd.New("vd")
data := &T{}
err := v.Validate(data)
- assert.EqualError(t, err, "invalid parameter: A")
+ assertEqualError(t, err, "invalid parameter: A")
data.A = "b"
err = v.Validate(data)
- assert.EqualError(t, err, "invalid parameter: B")
+ assertEqualError(t, err, "invalid parameter: B")
data.B = 2
err = v.Validate(data)
- assert.NoError(t, err)
+ assertNoError(t, err)
type T2 struct {
C string `vd:"in($)"`
}
data2 := &T2{}
err = v.Validate(data2)
- assert.EqualError(t, err, "invalid parameter: C")
+ assertEqualError(t, err, "invalid parameter: C")
type T3 struct {
C string `vd:"in($,1)"`
}
data3 := &T3{}
err = v.Validate(data3)
- assert.EqualError(t, err, "invalid parameter: C")
+ assertEqualError(t, err, "invalid parameter: C")
}
type (
@@ -220,7 +236,7 @@ type (
func TestIssue23(t *testing.T) {
var data = &Issue23B{a: &Issue23A{b: new(Issue23B)}}
err := vd.Validate(data, true)
- assert.NoError(t, err)
+ assertNoError(t, err)
}
func TestIssue24(t *testing.T) {
@@ -253,7 +269,7 @@ func TestIssue24(t *testing.T) {
}
var data = &SubmitDoctorImportRequest{SubmitDoctorImport: []*SubmitDoctorImportItem{{}}}
err := vd.Validate(data, true)
- assert.EqualError(t, err, "invalid parameter: SubmitDoctorImport[0].Idcard\tinvalid parameter: SubmitDoctorImport[0].PracCertNo\temail format is incorrect\tthe phone number supplied is not a number")
+ assertEqualError(t, err, "invalid parameter: SubmitDoctorImport[0].Idcard\tinvalid parameter: SubmitDoctorImport[0].PracCertNo\temail format is incorrect\tthe phone number supplied is not a number")
}
func TestStructSliceMap(t *testing.T) {
@@ -276,7 +292,7 @@ func TestStructSliceMap(t *testing.T) {
C: map[string][]map[string]F{"z": {{"zz": *f}}},
}
err := vd.Validate(s, true)
- assert.EqualError(t, err, "invalid parameter: A{v for k=x}.f.g\tinvalid parameter: B[0]{v for k=y}.f.g\tinvalid parameter: C{v for k=z}[0]{v for k=zz}.f.g")
+ assertEqualError(t, err, "invalid parameter: A{v for k=x}.f.g\tinvalid parameter: B[0]{v for k=y}.f.g\tinvalid parameter: C{v for k=z}[0]{v for k=zz}.f.g")
}
func TestIssue30(t *testing.T) {
@@ -287,27 +303,27 @@ func TestIssue30(t *testing.T) {
vd.RegFunc("gt", func(args ...interface{}) error {
return errors.New("force error")
})
- assert.EqualError(t, vd.Validate(&TStruct{TOk: "1"}), "invalid parameter: TOk")
- // assert.NoError(t, vd.Validate(&TStruct{TOk: "1", TFail: "1"}))
+ assertEqualError(t, vd.Validate(&TStruct{TOk: "1"}), "invalid parameter: TOk")
+ // assertNoError(t, vd.Validate(&TStruct{TOk: "1", TFail: "1"}))
}
func TestIssue31(t *testing.T) {
type TStruct struct {
A []int32 `vd:"$ == nil || ($ != nil && range($, in(#v, 1, 2, 3))"`
}
- assert.EqualError(t, vd.Validate(&TStruct{A: []int32{1}}), "syntax error: \"($ != nil && range($, in(#v, 1, 2, 3))\"")
- assert.EqualError(t, vd.Validate(&TStruct{A: []int32{1}}), "syntax error: \"($ != nil && range($, in(#v, 1, 2, 3))\"")
- assert.EqualError(t, vd.Validate(&TStruct{A: []int32{1}}), "syntax error: \"($ != nil && range($, in(#v, 1, 2, 3))\"")
+ assertEqualError(t, vd.Validate(&TStruct{A: []int32{1}}), "syntax error: \"($ != nil && range($, in(#v, 1, 2, 3))\"")
+ assertEqualError(t, vd.Validate(&TStruct{A: []int32{1}}), "syntax error: \"($ != nil && range($, in(#v, 1, 2, 3))\"")
+ assertEqualError(t, vd.Validate(&TStruct{A: []int32{1}}), "syntax error: \"($ != nil && range($, in(#v, 1, 2, 3))\"")
}
func TestRegexp(t *testing.T) {
type TStruct struct {
A string `vd:"regexp('(\\d+\\.){3}\\d+')"`
}
- assert.NoError(t, vd.Validate(&TStruct{A: "0.0.0.0"}))
- assert.EqualError(t, vd.Validate(&TStruct{A: "0...0"}), "invalid parameter: A")
- assert.EqualError(t, vd.Validate(&TStruct{A: "abc1"}), "invalid parameter: A")
- assert.EqualError(t, vd.Validate(&TStruct{A: "0?0?0?0"}), "invalid parameter: A")
+ assertNoError(t, vd.Validate(&TStruct{A: "0.0.0.0"}))
+ assertEqualError(t, vd.Validate(&TStruct{A: "0...0"}), "invalid parameter: A")
+ assertEqualError(t, vd.Validate(&TStruct{A: "abc1"}), "invalid parameter: A")
+ assertEqualError(t, vd.Validate(&TStruct{A: "0?0?0?0"}), "invalid parameter: A")
}
func TestRangeIn(t *testing.T) {
@@ -317,9 +333,9 @@ func TestRangeIn(t *testing.T) {
err := vd.Validate(S{
F: []string{"ttp", "", "euttp"},
})
- assert.NoError(t, err)
+ assertNoError(t, err)
err = vd.Validate(S{
F: []string{"ttp", "?", "euttp"},
})
- assert.EqualError(t, err, "invalid parameter: F")
+ assertEqualError(t, err, "invalid parameter: F")
}
diff --git a/pkg/app/server/binding/config.go b/pkg/app/server/binding/config.go
index 81cf30e56..4ee349e93 100644
--- a/pkg/app/server/binding/config.go
+++ b/pkg/app/server/binding/config.go
@@ -22,7 +22,7 @@ import (
"reflect"
"time"
- exprValidator "github.com/bytedance/go-tagexpr/v2/validator"
+ exprValidator "github.com/cloudwego/hertz/internal/tagexpr/validator"
inDecoder "github.com/cloudwego/hertz/pkg/app/server/binding/internal/decoder"
hJson "github.com/cloudwego/hertz/pkg/common/json"
"github.com/cloudwego/hertz/pkg/protocol"
diff --git a/pkg/app/server/binding/default.go b/pkg/app/server/binding/default.go
index 7e09ac9bb..42f55ee87 100644
--- a/pkg/app/server/binding/default.go
+++ b/pkg/app/server/binding/default.go
@@ -70,8 +70,8 @@ import (
"strings"
"sync"
- exprValidator "github.com/bytedance/go-tagexpr/v2/validator"
"github.com/cloudwego/hertz/internal/bytesconv"
+ exprValidator "github.com/cloudwego/hertz/internal/tagexpr/validator"
inDecoder "github.com/cloudwego/hertz/pkg/app/server/binding/internal/decoder"
hJson "github.com/cloudwego/hertz/pkg/common/json"
"github.com/cloudwego/hertz/pkg/common/utils"