mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2025-12-31 01:10:20 -06:00
Bump github.com/gookit/config/v2 from 2.2.3 to 2.2.4
Bumps [github.com/gookit/config/v2](https://github.com/gookit/config) from 2.2.3 to 2.2.4. - [Release notes](https://github.com/gookit/config/releases) - [Commits](https://github.com/gookit/config/compare/v2.2.3...v2.2.4) --- updated-dependencies: - dependency-name: github.com/gookit/config/v2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
committed by
Ralf Haferkamp
parent
30784affc4
commit
0df009eae0
8
go.mod
8
go.mod
@@ -44,7 +44,7 @@ require (
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/google/go-tika v0.3.0
|
||||
github.com/google/uuid v1.4.0
|
||||
github.com/gookit/config/v2 v2.2.3
|
||||
github.com/gookit/config/v2 v2.2.4
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0
|
||||
github.com/jellydator/ttlcache/v2 v2.11.1
|
||||
@@ -204,7 +204,7 @@ require (
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.0.4 // indirect
|
||||
github.com/goccy/go-yaml v1.11.0 // indirect
|
||||
github.com/goccy/go-yaml v1.11.2 // indirect
|
||||
github.com/godbus/dbus/v5 v5.0.6 // indirect
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
@@ -217,8 +217,8 @@ require (
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
|
||||
github.com/google/renameio/v2 v2.0.0 // indirect
|
||||
github.com/gookit/color v1.5.3 // indirect
|
||||
github.com/gookit/goutil v0.6.10 // indirect
|
||||
github.com/gookit/color v1.5.4 // indirect
|
||||
github.com/gookit/goutil v0.6.14 // indirect
|
||||
github.com/gorilla/handlers v1.5.1 // indirect
|
||||
github.com/gorilla/schema v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||
|
||||
16
go.sum
16
go.sum
@@ -1244,8 +1244,8 @@ github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm
|
||||
github.com/gobwas/ws v1.0.4 h1:5eXU1CZhpQdq5kXbKb+sECH5Ia5KiO6CYzIzdlVx6Bs=
|
||||
github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-yaml v1.11.0 h1:n7Z+zx8S9f9KgzG6KtQKf+kwqXZlLNR2F6018Dgau54=
|
||||
github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFTWckfng=
|
||||
github.com/goccy/go-yaml v1.11.2 h1:joq77SxuyIs9zzxEjgyLBugMQ9NEgTWxXfz2wVqwAaQ=
|
||||
github.com/goccy/go-yaml v1.11.2/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.6 h1:mkgN1ofwASrYnJ5W6U/BxG15eXXXjirgZc7CLqkcaro=
|
||||
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
@@ -1404,12 +1404,12 @@ github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5i
|
||||
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
|
||||
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
|
||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||
github.com/gookit/color v1.5.3 h1:twfIhZs4QLCtimkP7MOxlF3A0U/5cDPseRT9M/+2SCE=
|
||||
github.com/gookit/color v1.5.3/go.mod h1:NUzwzeehUfl7GIb36pqId+UGmRfQcU/WiiyTTeNjHtE=
|
||||
github.com/gookit/config/v2 v2.2.3 h1:GlnYPduYeY7lRgWQmGld9juy0xpFUo06BUC9Pzyjuew=
|
||||
github.com/gookit/config/v2 v2.2.3/go.mod h1:FhmMu+2wg0UhyOjVGo+DZ1+ov34q4G4aWXzh86boEsY=
|
||||
github.com/gookit/goutil v0.6.10 h1:iq7CXOf+fYLvrVAh3+ZoLgufGfK65TwbzE8NpnPGtyk=
|
||||
github.com/gookit/goutil v0.6.10/go.mod h1:qqrPoX+Pm6YmxqqccgkNLPirTFX7UYMES1SK+fokqQU=
|
||||
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
|
||||
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
|
||||
github.com/gookit/config/v2 v2.2.4 h1:uLHNzFzREe5gDBP4Gb1+WOC9LB6vauPvq4eolp32Dcg=
|
||||
github.com/gookit/config/v2 v2.2.4/go.mod h1:k1ofSAuJnW6n1kTriFMSzFDC8ZT20tAPQ+1iGI3QOrU=
|
||||
github.com/gookit/goutil v0.6.14 h1:96elyOG4BvVoDaiT7vx1vHPrVyEtFfYlPPBODR0/FGQ=
|
||||
github.com/gookit/goutil v0.6.14/go.mod h1:YyDBddefmjS+mU2PDPgCcjVzTDM5WgExiDv5ZA/b8I8=
|
||||
github.com/gookit/ini/v2 v2.2.2 h1:3B8abZJrVH1vi/7TU4STuTBxdhiAq1ORSt6NJZCahaI=
|
||||
github.com/gophercloud/gophercloud v0.15.1-0.20210202035223-633d73521055/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4=
|
||||
github.com/gophercloud/gophercloud v0.16.0/go.mod h1:wRtmUelyIIv3CSSDI47aUwbs075O6i+LY+pXsKCBsb4=
|
||||
|
||||
23
vendor/github.com/goccy/go-yaml/CHANGELOG.md
generated
vendored
23
vendor/github.com/goccy/go-yaml/CHANGELOG.md
generated
vendored
@@ -1,3 +1,26 @@
|
||||
# 1.11.2 - 2023-09-15
|
||||
|
||||
### Fix bugs
|
||||
|
||||
- Fix quoted comments ( #370 )
|
||||
- Fix handle of space at start or last ( #376 )
|
||||
- Fix sequence with comment ( #390 )
|
||||
|
||||
# 1.11.1 - 2023-09-14
|
||||
|
||||
### Fix bugs
|
||||
|
||||
- Handle `\r` in a double-quoted string the same as `\n` ( #372 )
|
||||
- Replace loop with n.Values = append(n.Values, target.Values...) ( #380 )
|
||||
- Skip encoding an inline field if it is null ( #386 )
|
||||
- Fix comment parsing with null value ( #388 )
|
||||
|
||||
# 1.11.0 - 2023-04-03
|
||||
|
||||
### Features
|
||||
|
||||
- Supports dynamically switch encode and decode processing for a given type
|
||||
|
||||
# 1.10.1 - 2023-03-28
|
||||
|
||||
### Features
|
||||
|
||||
4
vendor/github.com/goccy/go-yaml/ast/ast.go
generated
vendored
4
vendor/github.com/goccy/go-yaml/ast/ast.go
generated
vendored
@@ -1506,9 +1506,7 @@ func (n *SequenceNode) Replace(idx int, value Node) error {
|
||||
func (n *SequenceNode) Merge(target *SequenceNode) {
|
||||
column := n.Start.Position.Column - target.Start.Position.Column
|
||||
target.AddColumn(column)
|
||||
for _, value := range target.Values {
|
||||
n.Values = append(n.Values, value)
|
||||
}
|
||||
n.Values = append(n.Values, target.Values...)
|
||||
}
|
||||
|
||||
// SetIsFlowStyle set value to IsFlowStyle field recursively.
|
||||
|
||||
4
vendor/github.com/goccy/go-yaml/encode.go
generated
vendored
4
vendor/github.com/goccy/go-yaml/encode.go
generated
vendored
@@ -823,6 +823,10 @@ func (e *Encoder) encodeStruct(ctx context.Context, value reflect.Value, column
|
||||
}
|
||||
mapNode, ok := value.(ast.MapNode)
|
||||
if !ok {
|
||||
// if an inline field is null, skip encoding it
|
||||
if _, ok := value.(*ast.NullNode); ok {
|
||||
continue
|
||||
}
|
||||
return nil, xerrors.Errorf("inline value is must be map or struct type")
|
||||
}
|
||||
mapIter := mapNode.MapRange()
|
||||
|
||||
7
vendor/github.com/goccy/go-yaml/parser/context.go
generated
vendored
7
vendor/github.com/goccy/go-yaml/parser/context.go
generated
vendored
@@ -13,7 +13,6 @@ type context struct {
|
||||
idx int
|
||||
size int
|
||||
tokens token.Tokens
|
||||
mode Mode
|
||||
path string
|
||||
}
|
||||
|
||||
@@ -56,7 +55,6 @@ func (c *context) copy() *context {
|
||||
idx: c.idx,
|
||||
size: c.size,
|
||||
tokens: append(token.Tokens{}, c.tokens...),
|
||||
mode: c.mode,
|
||||
path: c.path,
|
||||
}
|
||||
}
|
||||
@@ -145,10 +143,6 @@ func (c *context) afterNextNotCommentToken() *token.Token {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *context) enabledComment() bool {
|
||||
return c.mode&ParseComments != 0
|
||||
}
|
||||
|
||||
func (c *context) isCurrentCommentToken() bool {
|
||||
tk := c.currentToken()
|
||||
if tk == nil {
|
||||
@@ -193,7 +187,6 @@ func newContext(tokens token.Tokens, mode Mode) *context {
|
||||
idx: 0,
|
||||
size: len(filteredTokens),
|
||||
tokens: token.Tokens(filteredTokens),
|
||||
mode: mode,
|
||||
path: "$",
|
||||
}
|
||||
}
|
||||
|
||||
41
vendor/github.com/goccy/go-yaml/parser/parser.go
generated
vendored
41
vendor/github.com/goccy/go-yaml/parser/parser.go
generated
vendored
@@ -156,15 +156,38 @@ func (p *parser) createMapValueNode(ctx *context, key ast.MapKeyNode, colonToken
|
||||
ctx.insertToken(ctx.idx, nullToken)
|
||||
return ast.Null(nullToken), nil
|
||||
}
|
||||
|
||||
var comment *ast.CommentGroupNode
|
||||
if tk.Type == token.CommentType {
|
||||
comment = p.parseCommentOnly(ctx)
|
||||
if comment != nil {
|
||||
comment.SetPath(ctx.withChild(key.GetToken().Value).path)
|
||||
}
|
||||
tk = ctx.currentToken()
|
||||
}
|
||||
if tk.Position.Column == key.GetToken().Position.Column && tk.Type == token.StringType {
|
||||
// in this case,
|
||||
// ----
|
||||
// key: <value does not defined>
|
||||
// next
|
||||
|
||||
nullToken := p.createNullToken(colonToken)
|
||||
ctx.insertToken(ctx.idx, nullToken)
|
||||
return ast.Null(nullToken), nil
|
||||
nullNode := ast.Null(nullToken)
|
||||
|
||||
if comment != nil {
|
||||
nullNode.SetComment(comment)
|
||||
} else {
|
||||
// If there is a comment, it is already bound to the key node,
|
||||
// so remove the comment from the key to bind it to the null value.
|
||||
keyComment := key.GetComment()
|
||||
if keyComment != nil {
|
||||
if err := key.SetComment(nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nullNode.SetComment(keyComment)
|
||||
}
|
||||
}
|
||||
return nullNode, nil
|
||||
}
|
||||
|
||||
if tk.Position.Column < key.GetToken().Position.Column {
|
||||
@@ -174,13 +197,20 @@ func (p *parser) createMapValueNode(ctx *context, key ast.MapKeyNode, colonToken
|
||||
// next
|
||||
nullToken := p.createNullToken(colonToken)
|
||||
ctx.insertToken(ctx.idx, nullToken)
|
||||
return ast.Null(nullToken), nil
|
||||
nullNode := ast.Null(nullToken)
|
||||
if comment != nil {
|
||||
nullNode.SetComment(comment)
|
||||
}
|
||||
return nullNode, nil
|
||||
}
|
||||
|
||||
value, err := p.parseToken(ctx, ctx.currentToken())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to parse mapping 'value' node")
|
||||
}
|
||||
if comment != nil {
|
||||
value.SetComment(comment)
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
@@ -304,10 +334,9 @@ func (p *parser) parseSequenceEntry(ctx *context) (*ast.SequenceNode, error) {
|
||||
if tk.Type == token.CommentType {
|
||||
comment = p.parseCommentOnly(ctx)
|
||||
tk = ctx.currentToken()
|
||||
if tk.Type != token.SequenceEntryType {
|
||||
break
|
||||
if tk.Type == token.SequenceEntryType {
|
||||
ctx.progress(1) // skip sequence token
|
||||
}
|
||||
ctx.progress(1) // skip sequence token
|
||||
}
|
||||
value, err := p.parseToken(ctx.withIndex(uint(len(sequenceNode.Values))), ctx.currentToken())
|
||||
if err != nil {
|
||||
|
||||
26
vendor/github.com/goccy/go-yaml/path.go
generated
vendored
26
vendor/github.com/goccy/go-yaml/path.go
generated
vendored
@@ -500,11 +500,29 @@ func newSelectorNode(selector string) *selectorNode {
|
||||
}
|
||||
|
||||
func (n *selectorNode) filter(node ast.Node) (ast.Node, error) {
|
||||
selector := n.selector
|
||||
if len(selector) > 1 && selector[0] == '\'' && selector[len(selector)-1] == '\'' {
|
||||
selector = selector[1 : len(selector)-1]
|
||||
}
|
||||
switch node.Type() {
|
||||
case ast.MappingType:
|
||||
for _, value := range node.(*ast.MappingNode).Values {
|
||||
key := value.Key.GetToken().Value
|
||||
if key == n.selector {
|
||||
if len(key) > 0 {
|
||||
switch key[0] {
|
||||
case '"':
|
||||
var err error
|
||||
key, err = strconv.Unquote(key)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to unquote")
|
||||
}
|
||||
case '\'':
|
||||
if len(key) > 1 && key[len(key)-1] == '\'' {
|
||||
key = key[1 : len(key)-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
if key == selector {
|
||||
if n.child == nil {
|
||||
return value.Value, nil
|
||||
}
|
||||
@@ -518,7 +536,7 @@ func (n *selectorNode) filter(node ast.Node) (ast.Node, error) {
|
||||
case ast.MappingValueType:
|
||||
value := node.(*ast.MappingValueNode)
|
||||
key := value.Key.GetToken().Value
|
||||
if key == n.selector {
|
||||
if key == selector {
|
||||
if n.child == nil {
|
||||
return value.Value, nil
|
||||
}
|
||||
@@ -571,7 +589,9 @@ func (n *selectorNode) replace(node ast.Node, target ast.Node) error {
|
||||
}
|
||||
|
||||
func (n *selectorNode) String() string {
|
||||
s := fmt.Sprintf(".%s", n.selector)
|
||||
var builder PathBuilder
|
||||
selector := builder.normalizeSelectorName(n.selector)
|
||||
s := fmt.Sprintf(".%s", selector)
|
||||
if n.child != nil {
|
||||
s += n.child.String()
|
||||
}
|
||||
|
||||
5
vendor/github.com/goccy/go-yaml/scanner/scanner.go
generated
vendored
5
vendor/github.com/goccy/go-yaml/scanner/scanner.go
generated
vendored
@@ -339,6 +339,11 @@ func (s *Scanner) scanDoubleQuote(ctx *Context) (tk *token.Token, pos int) {
|
||||
value = append(value, '\n')
|
||||
idx++
|
||||
continue
|
||||
case 'r':
|
||||
ctx.addOriginBuf(nextChar)
|
||||
value = append(value, '\r')
|
||||
idx++
|
||||
continue
|
||||
case 'v':
|
||||
ctx.addOriginBuf(nextChar)
|
||||
value = append(value, '\v')
|
||||
|
||||
4
vendor/github.com/goccy/go-yaml/token/token.go
generated
vendored
4
vendor/github.com/goccy/go-yaml/token/token.go
generated
vendored
@@ -623,12 +623,12 @@ func IsNeedQuoted(value string) bool {
|
||||
}
|
||||
first := value[0]
|
||||
switch first {
|
||||
case '*', '&', '[', '{', '}', ']', ',', '!', '|', '>', '%', '\'', '"', '@':
|
||||
case '*', '&', '[', '{', '}', ']', ',', '!', '|', '>', '%', '\'', '"', '@', ' ':
|
||||
return true
|
||||
}
|
||||
last := value[len(value)-1]
|
||||
switch last {
|
||||
case ':':
|
||||
case ':', ' ':
|
||||
return true
|
||||
}
|
||||
if looksLikeTimeValue(value) {
|
||||
|
||||
62
vendor/github.com/goccy/go-yaml/yaml.go
generated
vendored
62
vendor/github.com/goccy/go-yaml/yaml.go
generated
vendored
@@ -89,43 +89,42 @@ func (s MapSlice) ToMap() map[interface{}]interface{} {
|
||||
//
|
||||
// The field tag format accepted is:
|
||||
//
|
||||
// `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
|
||||
// `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
|
||||
//
|
||||
// The following flags are currently supported:
|
||||
//
|
||||
// omitempty Only include the field if it's not set to the zero
|
||||
// value for the type or to empty slices or maps.
|
||||
// Zero valued structs will be omitted if all their public
|
||||
// fields are zero, unless they implement an IsZero
|
||||
// method (see the IsZeroer interface type), in which
|
||||
// case the field will be included if that method returns true.
|
||||
// omitempty Only include the field if it's not set to the zero
|
||||
// value for the type or to empty slices or maps.
|
||||
// Zero valued structs will be omitted if all their public
|
||||
// fields are zero, unless they implement an IsZero
|
||||
// method (see the IsZeroer interface type), in which
|
||||
// case the field will be included if that method returns true.
|
||||
//
|
||||
// flow Marshal using a flow style (useful for structs,
|
||||
// sequences and maps).
|
||||
// flow Marshal using a flow style (useful for structs,
|
||||
// sequences and maps).
|
||||
//
|
||||
// inline Inline the field, which must be a struct or a map,
|
||||
// causing all of its fields or keys to be processed as if
|
||||
// they were part of the outer struct. For maps, keys must
|
||||
// not conflict with the yaml keys of other struct fields.
|
||||
// inline Inline the field, which must be a struct or a map,
|
||||
// causing all of its fields or keys to be processed as if
|
||||
// they were part of the outer struct. For maps, keys must
|
||||
// not conflict with the yaml keys of other struct fields.
|
||||
//
|
||||
// anchor Marshal with anchor. If want to define anchor name explicitly, use anchor=name style.
|
||||
// Otherwise, if used 'anchor' name only, used the field name lowercased as the anchor name
|
||||
// anchor Marshal with anchor. If want to define anchor name explicitly, use anchor=name style.
|
||||
// Otherwise, if used 'anchor' name only, used the field name lowercased as the anchor name
|
||||
//
|
||||
// alias Marshal with alias. If want to define alias name explicitly, use alias=name style.
|
||||
// Otherwise, If omitted alias name and the field type is pointer type,
|
||||
// assigned anchor name automatically from same pointer address.
|
||||
// alias Marshal with alias. If want to define alias name explicitly, use alias=name style.
|
||||
// Otherwise, If omitted alias name and the field type is pointer type,
|
||||
// assigned anchor name automatically from same pointer address.
|
||||
//
|
||||
// In addition, if the key is "-", the field is ignored.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// type T struct {
|
||||
// F int `yaml:"a,omitempty"`
|
||||
// B int
|
||||
// }
|
||||
// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
|
||||
// yaml.Marshal(&T{F: 1}) // Returns "a: 1\nb: 0\n"
|
||||
//
|
||||
// type T struct {
|
||||
// F int `yaml:"a,omitempty"`
|
||||
// B int
|
||||
// }
|
||||
// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
|
||||
// yaml.Marshal(&T{F: 1}) // Returns "a: 1\nb: 0\n"
|
||||
func Marshal(v interface{}) ([]byte, error) {
|
||||
return MarshalWithOptions(v)
|
||||
}
|
||||
@@ -167,16 +166,15 @@ func ValueToNode(v interface{}, opts ...EncodeOption) (ast.Node, error) {
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// type T struct {
|
||||
// F int `yaml:"a,omitempty"`
|
||||
// B int
|
||||
// }
|
||||
// var t T
|
||||
// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
|
||||
// type T struct {
|
||||
// F int `yaml:"a,omitempty"`
|
||||
// B int
|
||||
// }
|
||||
// var t T
|
||||
// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
|
||||
//
|
||||
// See the documentation of Marshal for the format of tags and a list of
|
||||
// supported tag options.
|
||||
//
|
||||
func Unmarshal(data []byte, v interface{}) error {
|
||||
return UnmarshalWithOptions(data, v)
|
||||
}
|
||||
|
||||
49
vendor/github.com/gookit/color/color_16.go
generated
vendored
49
vendor/github.com/gookit/color/color_16.go
generated
vendored
@@ -41,15 +41,27 @@ func (o Opts) String() string {
|
||||
* Basic 16 color definition
|
||||
*************************************************************/
|
||||
|
||||
// Base value for foreground/background color
|
||||
// base: fg 30~37, bg 40~47
|
||||
// light: fg 90~97, bg 100~107
|
||||
const (
|
||||
// OptMax max option value. range: 0 - 9
|
||||
OptMax = 10
|
||||
// DiffFgBg diff foreground and background color
|
||||
DiffFgBg = 10
|
||||
)
|
||||
|
||||
// Boundary value for foreground/background color 16
|
||||
//
|
||||
// - base: fg 30~37, bg 40~47
|
||||
// - light: fg 90~97, bg 100~107
|
||||
const (
|
||||
FgBase uint8 = 30
|
||||
FgMax uint8 = 37
|
||||
BgBase uint8 = 40
|
||||
BgMax uint8 = 47
|
||||
|
||||
HiFgBase uint8 = 90
|
||||
HiFgMax uint8 = 97
|
||||
HiBgBase uint8 = 100
|
||||
HiBgMax uint8 = 107
|
||||
)
|
||||
|
||||
// Foreground colors. basic foreground colors 30 - 37
|
||||
@@ -94,7 +106,7 @@ const (
|
||||
BgDefault Color = 49
|
||||
)
|
||||
|
||||
// Extra background color 100 - 107(非标准)
|
||||
// Extra background color 100 - 107 (non-standard)
|
||||
const (
|
||||
BgDarkGray Color = iota + 100
|
||||
BgLightRed
|
||||
@@ -108,7 +120,7 @@ const (
|
||||
BgGray Color = 100
|
||||
)
|
||||
|
||||
// Option settings
|
||||
// Option settings. range: 0 - 9
|
||||
const (
|
||||
OpReset Color = iota // 0 重置所有设置
|
||||
OpBold // 1 加粗
|
||||
@@ -248,9 +260,9 @@ func (c Color) Println(a ...any) { doPrintlnV2(c.String(), a) }
|
||||
// lightCyan := Cyan.Light()
|
||||
// lightCyan.Print("message")
|
||||
func (c Color) Light() Color {
|
||||
val := int(c)
|
||||
val := uint8(c)
|
||||
if val >= 30 && val <= 47 {
|
||||
return Color(uint8(c) + 60)
|
||||
return Color(val + 60)
|
||||
}
|
||||
|
||||
// don't change
|
||||
@@ -264,9 +276,9 @@ func (c Color) Light() Color {
|
||||
// cyan := LightCyan.Darken()
|
||||
// cyan.Print("message")
|
||||
func (c Color) Darken() Color {
|
||||
val := int(c)
|
||||
val := uint8(c)
|
||||
if val >= 90 && val <= 107 {
|
||||
return Color(uint8(c) - 60)
|
||||
return Color(val - 60)
|
||||
}
|
||||
|
||||
// don't change
|
||||
@@ -324,7 +336,7 @@ func (c Color) RGB() RGBColor {
|
||||
return emptyRGBColor
|
||||
}
|
||||
|
||||
return HEX(Basic2hex(val))
|
||||
return HEX(Basic2hex(val), c.IsBg())
|
||||
}
|
||||
|
||||
// Code convert to code string. eg "35"
|
||||
@@ -337,8 +349,23 @@ func (c Color) String() string {
|
||||
return strconv.FormatInt(int64(c), 10)
|
||||
}
|
||||
|
||||
// IsBg check is background color
|
||||
func (c Color) IsBg() bool {
|
||||
val := uint8(c)
|
||||
return val >= BgBase && val <= BgMax || val >= HiBgBase && val <= HiBgMax
|
||||
}
|
||||
|
||||
// IsFg check is foreground color
|
||||
func (c Color) IsFg() bool {
|
||||
val := uint8(c)
|
||||
return val >= FgBase && val <= FgMax || val >= HiFgBase && val <= HiFgMax
|
||||
}
|
||||
|
||||
// IsOption check is option code: 0-9
|
||||
func (c Color) IsOption() bool { return uint8(c) < OptMax }
|
||||
|
||||
// IsValid color value
|
||||
func (c Color) IsValid() bool { return c < 107 }
|
||||
func (c Color) IsValid() bool { return uint8(c) < HiBgMax }
|
||||
|
||||
/*************************************************************
|
||||
* basic color maps
|
||||
|
||||
20
vendor/github.com/gookit/color/color_256.go
generated
vendored
20
vendor/github.com/gookit/color/color_256.go
generated
vendored
@@ -43,7 +43,8 @@ const (
|
||||
* 8bit(256) Color: Bit8Color Color256
|
||||
*************************************************************/
|
||||
|
||||
// Color256 256 color (8 bit), uint8 range at 0 - 255
|
||||
// Color256 256 color (8 bit), uint8 range at 0 - 255.
|
||||
// Support 256 color on windows CMD, PowerShell
|
||||
//
|
||||
// 颜色值使用10进制和16进制都可 0x98 = 152
|
||||
//
|
||||
@@ -54,10 +55,9 @@ const (
|
||||
//
|
||||
// example:
|
||||
//
|
||||
// fg color: [152, 0]
|
||||
// bg color: [152, 1]
|
||||
// fg color: [152, 0]
|
||||
// bg color: [152, 1]
|
||||
//
|
||||
// NOTICE: now support 256 color on windows CMD, PowerShell
|
||||
// lint warn - Name starts with package name
|
||||
type Color256 [2]uint8
|
||||
type Bit8Color = Color256 // alias
|
||||
@@ -164,9 +164,7 @@ func (c Color256) String() string {
|
||||
}
|
||||
|
||||
// IsFg color
|
||||
func (c Color256) IsFg() bool {
|
||||
return c[1] == AsFg
|
||||
}
|
||||
func (c Color256) IsFg() bool { return c[1] == AsFg }
|
||||
|
||||
// ToFg 256 color
|
||||
func (c Color256) ToFg() Color256 {
|
||||
@@ -175,9 +173,7 @@ func (c Color256) ToFg() Color256 {
|
||||
}
|
||||
|
||||
// IsBg color
|
||||
func (c Color256) IsBg() bool {
|
||||
return c[1] == AsBg
|
||||
}
|
||||
func (c Color256) IsBg() bool { return c[1] == AsBg }
|
||||
|
||||
// ToBg 256 color
|
||||
func (c Color256) ToBg() Color256 {
|
||||
@@ -186,9 +182,7 @@ func (c Color256) ToBg() Color256 {
|
||||
}
|
||||
|
||||
// IsEmpty value
|
||||
func (c Color256) IsEmpty() bool {
|
||||
return c[1] > 1
|
||||
}
|
||||
func (c Color256) IsEmpty() bool { return c[1] > 1 }
|
||||
|
||||
/*************************************************************
|
||||
* 8bit(256) Style
|
||||
|
||||
15
vendor/github.com/gookit/color/color_rgb.go
generated
vendored
15
vendor/github.com/gookit/color/color_rgb.go
generated
vendored
@@ -44,6 +44,7 @@ const (
|
||||
*************************************************************/
|
||||
|
||||
// RGBColor definition.
|
||||
// Support RGB color on Windows CMD, PowerShell
|
||||
//
|
||||
// The first to third digits represent the color value.
|
||||
// The last digit represents the foreground(0), background(1), >1 is unset value
|
||||
@@ -54,8 +55,6 @@ const (
|
||||
// // 3rd: Fg=0, Bg=1, >1: unset value
|
||||
// RGBColor{30,144,255, 0}
|
||||
// RGBColor{30,144,255, 1}
|
||||
//
|
||||
// NOTICE: now support RGB color on Windows CMD, PowerShell
|
||||
type RGBColor [4]uint8
|
||||
|
||||
// create an empty RGBColor
|
||||
@@ -251,6 +250,18 @@ func (c RGBColor) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// ToBg convert to background color
|
||||
func (c RGBColor) ToBg() RGBColor {
|
||||
c[3] = AsBg
|
||||
return c
|
||||
}
|
||||
|
||||
// ToFg convert to foreground color
|
||||
func (c RGBColor) ToFg() RGBColor {
|
||||
c[3] = AsFg
|
||||
return c
|
||||
}
|
||||
|
||||
// IsEmpty value
|
||||
func (c RGBColor) IsEmpty() bool {
|
||||
return c[3] > AsBg
|
||||
|
||||
24
vendor/github.com/gookit/color/convert.go
generated
vendored
24
vendor/github.com/gookit/color/convert.go
generated
vendored
@@ -52,6 +52,7 @@ var (
|
||||
|
||||
// ---------- basic(16) <=> RGB color convert ----------
|
||||
// refer from Hyper app
|
||||
// Tip: only keep foreground color, background color need convert to foreground color for convert to RGB
|
||||
basic2hexMap = map[uint8]string{
|
||||
30: "000000", // black
|
||||
31: "c51e14", // red
|
||||
@@ -61,7 +62,7 @@ var (
|
||||
35: "c839c5", // magenta
|
||||
36: "20c5c6", // cyan
|
||||
37: "c7c7c7", // white
|
||||
// - don't add bg color
|
||||
// - don't add bg color, convert to fg color for convert to RGB
|
||||
// 40: "000000", // black
|
||||
// 41: "c51e14", // red
|
||||
// 42: "1dc121", // green
|
||||
@@ -428,10 +429,11 @@ func HexToRGB(hex string) []int { return HexToRgb(hex) }
|
||||
// HexToRgb convert hex color string to RGB numbers
|
||||
//
|
||||
// Usage:
|
||||
// rgb := HexToRgb("ccc") // rgb: [204 204 204]
|
||||
// rgb := HexToRgb("aabbcc") // rgb: [170 187 204]
|
||||
// rgb := HexToRgb("#aabbcc") // rgb: [170 187 204]
|
||||
// rgb := HexToRgb("0xad99c0") // rgb: [170 187 204]
|
||||
//
|
||||
// rgb := HexToRgb("ccc") // rgb: [204 204 204]
|
||||
// rgb := HexToRgb("aabbcc") // rgb: [170 187 204]
|
||||
// rgb := HexToRgb("#aabbcc") // rgb: [170 187 204]
|
||||
// rgb := HexToRgb("0xad99c0") // rgb: [170 187 204]
|
||||
func HexToRgb(hex string) (rgb []int) {
|
||||
hex = strings.TrimSpace(hex)
|
||||
if hex == "" {
|
||||
@@ -474,6 +476,7 @@ func Rgb2hex(rgb []int) string { return RgbToHex(rgb) }
|
||||
// RgbToHex convert RGB-code to hex-code
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// hex := RgbToHex([]int{170, 187, 204}) // hex: "aabbcc"
|
||||
func RgbToHex(rgb []int) string {
|
||||
hexNodes := make([]string, len(rgb))
|
||||
@@ -488,10 +491,15 @@ func RgbToHex(rgb []int) string {
|
||||
* 4bit(16) color <=> RGB/True color
|
||||
*************************************************************/
|
||||
|
||||
// BasicToHex convert basic color to hex string.
|
||||
func BasicToHex(val uint8) string {
|
||||
val = Bg2Fg(val)
|
||||
return basic2hexMap[val]
|
||||
}
|
||||
|
||||
// Basic2hex convert basic color to hex string.
|
||||
func Basic2hex(val uint8) string {
|
||||
val = Fg2Bg(val)
|
||||
return basic2hexMap[val]
|
||||
return BasicToHex(val)
|
||||
}
|
||||
|
||||
// Hex2basic convert hex string to basic color code.
|
||||
@@ -663,6 +671,7 @@ func C256ToRgbV1(val uint8) (rgb []uint8) {
|
||||
// returns r, g, and b in the set [0, 255].
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// HslIntToRgb(0, 100, 50) // red
|
||||
// HslIntToRgb(120, 100, 50) // lime
|
||||
// HslIntToRgb(120, 100, 25) // dark green
|
||||
@@ -677,6 +686,7 @@ func HslIntToRgb(h, s, l int) (rgb []uint8) {
|
||||
// returns r, g, and b in the set [0, 255].
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// rgbVals := HslToRgb(0, 1, 0.5) // red
|
||||
func HslToRgb(h, s, l float64) (rgb []uint8) {
|
||||
var r, g, b float64
|
||||
|
||||
6
vendor/github.com/gookit/color/style.go
generated
vendored
6
vendor/github.com/gookit/color/style.go
generated
vendored
@@ -37,7 +37,8 @@ func (s *Style) Add(cs ...Color) {
|
||||
*s = append(*s, cs...)
|
||||
}
|
||||
|
||||
// Render render text
|
||||
// Render colored text
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// color.New(color.FgGreen).Render("text")
|
||||
@@ -46,8 +47,9 @@ func (s Style) Render(a ...any) string {
|
||||
return RenderCode(s.String(), a...)
|
||||
}
|
||||
|
||||
// Renderln render text line.
|
||||
// Renderln render text with newline.
|
||||
// like Println, will add spaces for each argument
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// color.New(color.FgGreen).Renderln("text", "more")
|
||||
|
||||
16
vendor/github.com/gookit/config/v2/export.go
generated
vendored
16
vendor/github.com/gookit/config/v2/export.go
generated
vendored
@@ -76,10 +76,21 @@ func (c *Config) MapOnExists(key string, dst any) error {
|
||||
//
|
||||
// dbInfo := Db{}
|
||||
// config.Structure("db", &dbInfo)
|
||||
func (c *Config) Structure(key string, dst any) error {
|
||||
func (c *Config) Structure(key string, dst any) (err error) {
|
||||
var data any
|
||||
// binding all data
|
||||
// binding all data on key is empty.
|
||||
if key == "" {
|
||||
// fix: if c.data is nil, don't need to apply map structure
|
||||
if len(c.data) == 0 {
|
||||
// init default value by tag: default
|
||||
if c.opts.ParseDefault {
|
||||
err = structs.InitDefaults(dst, func(opt *structs.InitOptions) {
|
||||
opt.ParseEnv = c.opts.ParseEnv
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
data = c.data
|
||||
} else {
|
||||
// binding sub-data of the config
|
||||
@@ -90,6 +101,7 @@ func (c *Config) Structure(key string, dst any) error {
|
||||
}
|
||||
}
|
||||
|
||||
// map structure from data
|
||||
bindConf := c.opts.makeDecoderConfig()
|
||||
// set result struct ptr
|
||||
bindConf.Result = dst
|
||||
|
||||
15
vendor/github.com/gookit/config/v2/read.go
generated
vendored
15
vendor/github.com/gookit/config/v2/read.go
generated
vendored
@@ -99,6 +99,21 @@ func (c *Config) Data() map[string]any {
|
||||
return c.data
|
||||
}
|
||||
|
||||
// Sub return sub config data by key
|
||||
func Sub(key string) map[string]any { return dc.Sub(key) }
|
||||
|
||||
// Sub get sub config data by key
|
||||
//
|
||||
// Note: will don't apply any options, like ParseEnv
|
||||
func (c *Config) Sub(key string) map[string]any {
|
||||
if mp, ok := c.GetValue(key); ok {
|
||||
if mmp, ok := mp.(map[string]any); ok {
|
||||
return mmp
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Keys return all config data
|
||||
func Keys() []string { return dc.Keys() }
|
||||
|
||||
|
||||
9
vendor/github.com/gookit/config/v2/util.go
generated
vendored
9
vendor/github.com/gookit/config/v2/util.go
generated
vendored
@@ -18,16 +18,21 @@ func ValDecodeHookFunc(parseEnv, parseTime bool) mapstructure.DecodeHookFunc {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
var err error
|
||||
str := data.(string)
|
||||
if parseEnv {
|
||||
str = envutil.ParseEnvValue(str)
|
||||
// https://docs.docker.com/compose/environment-variables/env-file/
|
||||
str, err = envutil.ParseOrErr(str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if len(str) < 2 {
|
||||
return str, nil
|
||||
}
|
||||
|
||||
// start char is number(1-9)
|
||||
if str[0] > '0' && str[0] < '9' {
|
||||
if str[0] > '0' && str[0] <= '9' {
|
||||
// parse time string. eg: 10s
|
||||
if parseTime && t.Kind() == reflect.Int64 {
|
||||
dur, err := time.ParseDuration(str)
|
||||
|
||||
1
vendor/github.com/gookit/goutil/.gitignore
generated
vendored
1
vendor/github.com/gookit/goutil/.gitignore
generated
vendored
@@ -20,3 +20,4 @@
|
||||
.DS_Store
|
||||
|
||||
testdata/
|
||||
vendor/
|
||||
1981
vendor/github.com/gookit/goutil/README.md
generated
vendored
1981
vendor/github.com/gookit/goutil/README.md
generated
vendored
File diff suppressed because it is too large
Load Diff
1969
vendor/github.com/gookit/goutil/README.zh-CN.md
generated
vendored
1969
vendor/github.com/gookit/goutil/README.zh-CN.md
generated
vendored
File diff suppressed because it is too large
Load Diff
114
vendor/github.com/gookit/goutil/arrutil/arrutil.go
generated
vendored
114
vendor/github.com/gookit/goutil/arrutil/arrutil.go
generated
vendored
@@ -2,95 +2,9 @@
|
||||
package arrutil
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
"github.com/gookit/goutil/mathutil"
|
||||
)
|
||||
|
||||
// Reverse string slice [site user info 0] -> [0 info user site]
|
||||
func Reverse(ss []string) {
|
||||
ln := len(ss)
|
||||
for i := 0; i < ln/2; i++ {
|
||||
li := ln - i - 1
|
||||
ss[i], ss[li] = ss[li], ss[i]
|
||||
}
|
||||
}
|
||||
|
||||
// StringsRemove a value form a string slice
|
||||
func StringsRemove(ss []string, s string) []string {
|
||||
ns := make([]string, 0, len(ss))
|
||||
for _, v := range ss {
|
||||
if v != s {
|
||||
ns = append(ns, v)
|
||||
}
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
// StringsFilter given strings, default will filter emtpy string.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// // output: [a, b]
|
||||
// ss := arrutil.StringsFilter([]string{"a", "", "b", ""})
|
||||
func StringsFilter(ss []string, filter ...func(s string) bool) []string {
|
||||
var fn func(s string) bool
|
||||
if len(filter) > 0 && filter[0] != nil {
|
||||
fn = filter[0]
|
||||
} else {
|
||||
fn = func(s string) bool {
|
||||
return s != ""
|
||||
}
|
||||
}
|
||||
|
||||
ns := make([]string, 0, len(ss))
|
||||
for _, s := range ss {
|
||||
if fn(s) {
|
||||
ns = append(ns, s)
|
||||
}
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
// StringsMap handle each string item, map to new strings
|
||||
func StringsMap(ss []string, mapFn func(s string) string) []string {
|
||||
ns := make([]string, 0, len(ss))
|
||||
for _, s := range ss {
|
||||
ns = append(ns, mapFn(s))
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
// TrimStrings trim string slice item.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// // output: [a, b, c]
|
||||
// ss := arrutil.TrimStrings([]string{",a", "b.", ",.c,"}, ",.")
|
||||
func TrimStrings(ss []string, cutSet ...string) []string {
|
||||
cutSetLn := len(cutSet)
|
||||
hasCutSet := cutSetLn > 0 && cutSet[0] != ""
|
||||
|
||||
var trimSet string
|
||||
if hasCutSet {
|
||||
trimSet = cutSet[0]
|
||||
}
|
||||
if cutSetLn > 1 {
|
||||
trimSet = strings.Join(cutSet, "")
|
||||
}
|
||||
|
||||
ns := make([]string, 0, len(ss))
|
||||
for _, str := range ss {
|
||||
if hasCutSet {
|
||||
ns = append(ns, strings.Trim(str, trimSet))
|
||||
} else {
|
||||
ns = append(ns, strings.TrimSpace(str))
|
||||
}
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
// GetRandomOne get random element from an array/slice
|
||||
func GetRandomOne[T any](arr []T) T { return RandomOne(arr) }
|
||||
|
||||
@@ -102,31 +16,3 @@ func RandomOne[T any](arr []T) T {
|
||||
}
|
||||
panic("cannot get value from nil or empty slice")
|
||||
}
|
||||
|
||||
// Unique value in the given slice data.
|
||||
func Unique[T ~string | comdef.XintOrFloat](list []T) []T {
|
||||
if len(list) < 2 {
|
||||
return list
|
||||
}
|
||||
|
||||
valMap := make(map[T]struct{}, len(list))
|
||||
uniArr := make([]T, 0, len(list))
|
||||
|
||||
for _, t := range list {
|
||||
if _, ok := valMap[t]; !ok {
|
||||
valMap[t] = struct{}{}
|
||||
uniArr = append(uniArr, t)
|
||||
}
|
||||
}
|
||||
return uniArr
|
||||
}
|
||||
|
||||
// IndexOf value in given slice.
|
||||
func IndexOf[T ~string | comdef.XintOrFloat](val T, list []T) int {
|
||||
for i, v := range list {
|
||||
if v == val {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
24
vendor/github.com/gookit/goutil/arrutil/check.go
generated
vendored
24
vendor/github.com/gookit/goutil/arrutil/check.go
generated
vendored
@@ -8,8 +8,18 @@ import (
|
||||
"github.com/gookit/goutil/mathutil"
|
||||
)
|
||||
|
||||
// IntsHas check the []int contains the given value
|
||||
func IntsHas(ints []int, val int) bool {
|
||||
// SliceHas check the slice contains the given value
|
||||
func SliceHas[T comdef.ScalarType](slice []T, val T) bool {
|
||||
for _, ele := range slice {
|
||||
if ele == val {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IntsHas check the []comdef.Integer contains the given value
|
||||
func IntsHas[T comdef.Integer](ints []T, val T) bool {
|
||||
for _, ele := range ints {
|
||||
if ele == val {
|
||||
return true
|
||||
@@ -28,11 +38,8 @@ func Int64sHas(ints []int64, val int64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// InStrings alias of StringsHas()
|
||||
func InStrings(elem string, ss []string) bool { return StringsHas(ss, elem) }
|
||||
|
||||
// StringsHas check the []string contains the given element
|
||||
func StringsHas(ss []string, val string) bool {
|
||||
func StringsHas[T ~string](ss []T, val T) bool {
|
||||
for _, ele := range ss {
|
||||
if ele == val {
|
||||
return true
|
||||
@@ -41,6 +48,11 @@ func StringsHas(ss []string, val string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// InStrings check elem in the ss. alias of StringsHas()
|
||||
func InStrings[T ~string](elem T, ss []T) bool {
|
||||
return StringsHas(ss, elem)
|
||||
}
|
||||
|
||||
// NotIn check the given value whether not in the list
|
||||
func NotIn[T comdef.ScalarType](value T, list []T) bool {
|
||||
return !In(value, list)
|
||||
|
||||
464
vendor/github.com/gookit/goutil/arrutil/collection.go
generated
vendored
464
vendor/github.com/gookit/goutil/arrutil/collection.go
generated
vendored
@@ -2,97 +2,72 @@ package arrutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
"github.com/gookit/goutil/reflects"
|
||||
)
|
||||
|
||||
// ErrElementNotFound is the error returned when the element is not found.
|
||||
const ErrElementNotFound = "element not found"
|
||||
var ErrElementNotFound = errors.New("element not found")
|
||||
|
||||
// Comparer Function to compare two elements.
|
||||
type Comparer func(a, b any) int
|
||||
type Comparer[T any] func(a, b T) int
|
||||
|
||||
// type Comparer func(a, b any) int
|
||||
|
||||
// Predicate Function to predicate a struct/value satisfies a condition.
|
||||
type Predicate func(a any) bool
|
||||
type Predicate[T any] func(v T) bool
|
||||
|
||||
var (
|
||||
// StringEqualsComparer Comparer for string. It will compare the string by their value.
|
||||
// returns: 0 if equal, -1 if a != b
|
||||
StringEqualsComparer Comparer = func(a, b any) int {
|
||||
typeOfA := reflect.TypeOf(a)
|
||||
if typeOfA.Kind() == reflect.Ptr {
|
||||
typeOfA = typeOfA.Elem()
|
||||
}
|
||||
|
||||
typeOfB := reflect.TypeOf(b)
|
||||
if typeOfB.Kind() == reflect.Ptr {
|
||||
typeOfB = typeOfB.Elem()
|
||||
}
|
||||
|
||||
if typeOfA != typeOfB {
|
||||
return -1
|
||||
}
|
||||
|
||||
strA := ""
|
||||
strB := ""
|
||||
|
||||
if val, ok := a.(string); ok {
|
||||
strA = val
|
||||
} else if val, ok := a.(*string); ok {
|
||||
strA = *val
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
|
||||
if val, ok := b.(string); ok {
|
||||
strB = val
|
||||
} else if val, ok := b.(*string); ok {
|
||||
strB = *val
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
|
||||
if strA == strB {
|
||||
return 0
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// ReferenceEqualsComparer Comparer for strcut ptr. It will compare the struct by their ptr addr.
|
||||
// returns: 0 if equal, -1 if a != b
|
||||
ReferenceEqualsComparer Comparer = func(a, b any) int {
|
||||
if a == b {
|
||||
return 0
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// ElemTypeEqualsComparer Comparer for struct/value. It will compare the struct by their element type (reflect.Type.Elem()).
|
||||
// returns: 0 if same type, -1 if not.
|
||||
ElemTypeEqualsComparer Comparer = func(a, b any) int {
|
||||
at := reflect.TypeOf(a)
|
||||
bt := reflect.TypeOf(b)
|
||||
if at.Kind() == reflect.Ptr {
|
||||
at = at.Elem()
|
||||
}
|
||||
|
||||
if bt.Kind() == reflect.Ptr {
|
||||
bt = bt.Elem()
|
||||
}
|
||||
|
||||
if at == bt {
|
||||
return 0
|
||||
}
|
||||
return -1
|
||||
}
|
||||
)
|
||||
|
||||
// TwowaySearch Find specialized element in a slice forward and backward in the same time, should be more quickly.
|
||||
// StringEqualsComparer Comparer for string. It will compare the string by their value.
|
||||
//
|
||||
// data: the slice to search in. MUST BE A SLICE.
|
||||
// item: the element to search.
|
||||
// fn: the comparer function.
|
||||
// return: the index of the element, or -1 if not found.
|
||||
func TwowaySearch(data any, item any, fn Comparer) (int, error) {
|
||||
// returns: 0 if equal, -1 if a != b
|
||||
func StringEqualsComparer(a, b string) int {
|
||||
if a == b {
|
||||
return 0
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// ValueEqualsComparer Comparer for comdef.Compared type. It will compare by their value.
|
||||
//
|
||||
// returns: 0 if equal, -1 if a != b
|
||||
func ValueEqualsComparer[T comdef.Compared](a, b T) int {
|
||||
if a == b {
|
||||
return 0
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// ReflectEqualsComparer Comparer for struct ptr. It will compare by reflect.Value
|
||||
//
|
||||
// returns: 0 if equal, -1 if a != b
|
||||
func ReflectEqualsComparer[T any](a, b T) int {
|
||||
if reflects.IsEqual(a, b) {
|
||||
return 0
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// ElemTypeEqualsComparer Comparer for struct/value. It will compare the struct by their element type.
|
||||
//
|
||||
// returns: 0 if same type, -1 if not.
|
||||
func ElemTypeEqualsComparer[T any](a, b T) int {
|
||||
at := reflects.TypeOf(a).SafeElem()
|
||||
bt := reflects.TypeOf(b).SafeElem()
|
||||
|
||||
if at == bt {
|
||||
return 0
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// TwowaySearch find specialized element in a slice forward and backward in the same time, should be more quickly.
|
||||
//
|
||||
// - data: the slice to search in. MUST BE A SLICE.
|
||||
// - item: the element to search.
|
||||
// - fn: the comparer function.
|
||||
// - return: the index of the element, or -1 if not found.
|
||||
func TwowaySearch[T any](data []T, item T, fn Comparer[T]) (int, error) {
|
||||
if data == nil {
|
||||
return -1, errors.New("collections.TwowaySearch: data is nil")
|
||||
}
|
||||
@@ -100,35 +75,19 @@ func TwowaySearch(data any, item any, fn Comparer) (int, error) {
|
||||
return -1, errors.New("collections.TwowaySearch: fn is nil")
|
||||
}
|
||||
|
||||
dataType := reflect.TypeOf(data)
|
||||
if dataType.Kind() != reflect.Slice {
|
||||
return -1, errors.New("collections.TwowaySearch: data is not a slice")
|
||||
}
|
||||
|
||||
dataVal := reflect.ValueOf(data)
|
||||
if dataVal.Len() == 0 {
|
||||
if len(data) == 0 {
|
||||
return -1, errors.New("collections.TwowaySearch: data is empty")
|
||||
}
|
||||
itemType := dataType.Elem()
|
||||
if itemType.Kind() == reflect.Ptr {
|
||||
itemType = itemType.Elem()
|
||||
}
|
||||
|
||||
if itemType != dataVal.Index(0).Type() {
|
||||
return -1, errors.New("collections.TwowaySearch: item type is not the same as data type")
|
||||
}
|
||||
|
||||
forward := 0
|
||||
backward := dataVal.Len() - 1
|
||||
backward := len(data) - 1
|
||||
|
||||
for forward <= backward {
|
||||
forwardVal := dataVal.Index(forward).Interface()
|
||||
if fn(forwardVal, item) == 0 {
|
||||
if fn(data[forward], item) == 0 {
|
||||
return forward, nil
|
||||
}
|
||||
|
||||
backwardVal := dataVal.Index(backward).Interface()
|
||||
if fn(backwardVal, item) == 0 {
|
||||
if fn(data[backward], item) == 0 {
|
||||
return backward, nil
|
||||
}
|
||||
|
||||
@@ -136,55 +95,44 @@ func TwowaySearch(data any, item any, fn Comparer) (int, error) {
|
||||
backward--
|
||||
}
|
||||
|
||||
return -1, errors.New(ErrElementNotFound)
|
||||
}
|
||||
|
||||
// MakeEmptySlice Create a new slice with the elements of the source that satisfy the predicate.
|
||||
//
|
||||
// itemType: the type of the elements in the source.
|
||||
// returns: the new slice.
|
||||
func MakeEmptySlice(itemType reflect.Type) any {
|
||||
ret := reflect.MakeSlice(reflect.SliceOf(itemType), 0, 0).Interface()
|
||||
return ret
|
||||
return -1, ErrElementNotFound
|
||||
}
|
||||
|
||||
// CloneSlice Clone a slice.
|
||||
//
|
||||
// data: the slice to clone.
|
||||
// returns: the cloned slice.
|
||||
func CloneSlice(data any) any {
|
||||
typeOfData := reflect.TypeOf(data)
|
||||
if typeOfData.Kind() != reflect.Slice {
|
||||
panic("collections.CloneSlice: data must be a slice")
|
||||
}
|
||||
return reflect.AppendSlice(reflect.New(reflect.SliceOf(typeOfData.Elem())).Elem(), reflect.ValueOf(data)).Interface()
|
||||
func CloneSlice[T any](data []T) []T {
|
||||
nt := make([]T, 0, len(data))
|
||||
nt = append(nt, data...)
|
||||
return nt
|
||||
}
|
||||
|
||||
// Diff Produces the set difference of two slice according to a comparer function. alias of Differences
|
||||
func Diff[T any](first, second []T, fn Comparer[T]) []T {
|
||||
return Differences(first, second, fn)
|
||||
}
|
||||
|
||||
// Differences Produces the set difference of two slice according to a comparer function.
|
||||
//
|
||||
// first: the first slice. MUST BE A SLICE.
|
||||
// second: the second slice. MUST BE A SLICE.
|
||||
// fn: the comparer function.
|
||||
// returns: the difference of the two slices.
|
||||
func Differences[T any](first, second []T, fn Comparer) []T {
|
||||
typeOfFirst := reflect.TypeOf(first)
|
||||
if typeOfFirst.Kind() != reflect.Slice {
|
||||
panic("collections.Excepts: first must be a slice")
|
||||
}
|
||||
|
||||
typeOfSecond := reflect.TypeOf(second)
|
||||
if typeOfSecond.Kind() != reflect.Slice {
|
||||
panic("collections.Excepts: second must be a slice")
|
||||
}
|
||||
|
||||
// - first: the first slice. MUST BE A SLICE.
|
||||
// - second: the second slice. MUST BE A SLICE.
|
||||
// - fn: the comparer function.
|
||||
// - returns: the difference of the two slices.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Output: []string{"c"}
|
||||
// Differences([]string{"a", "b", "c"}, []string{"a", "b"}, arrutil.StringEqualsComparer
|
||||
func Differences[T any](first, second []T, fn Comparer[T]) []T {
|
||||
firstLen := len(first)
|
||||
if firstLen == 0 {
|
||||
return CloneSlice(second).([]T)
|
||||
return CloneSlice(second)
|
||||
}
|
||||
|
||||
secondLen := len(second)
|
||||
if secondLen == 0 {
|
||||
return CloneSlice(first).([]T)
|
||||
return CloneSlice(first)
|
||||
}
|
||||
|
||||
max := firstLen
|
||||
@@ -214,139 +162,123 @@ func Differences[T any](first, second []T, fn Comparer) []T {
|
||||
|
||||
// Excepts Produces the set difference of two slice according to a comparer function.
|
||||
//
|
||||
// first: the first slice. MUST BE A SLICE.
|
||||
// second: the second slice. MUST BE A SLICE.
|
||||
// fn: the comparer function.
|
||||
// returns: the difference of the two slices.
|
||||
func Excepts(first, second any, fn Comparer) any {
|
||||
typeOfFirst := reflect.TypeOf(first)
|
||||
if typeOfFirst.Kind() != reflect.Slice {
|
||||
panic("collections.Excepts: first must be a slice")
|
||||
// - first: the first slice. MUST BE A SLICE.
|
||||
// - second: the second slice. MUST BE A SLICE.
|
||||
// - fn: the comparer function.
|
||||
// - returns: the difference of the two slices.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Output: []string{"c"}
|
||||
// Excepts([]string{"a", "b", "c"}, []string{"a", "b"}, arrutil.StringEqualsComparer)
|
||||
func Excepts[T any](first, second []T, fn Comparer[T]) []T {
|
||||
if len(first) == 0 {
|
||||
return make([]T, 0)
|
||||
}
|
||||
valOfFirst := reflect.ValueOf(first)
|
||||
if valOfFirst.Len() == 0 {
|
||||
return MakeEmptySlice(typeOfFirst.Elem())
|
||||
}
|
||||
|
||||
typeOfSecond := reflect.TypeOf(second)
|
||||
if typeOfSecond.Kind() != reflect.Slice {
|
||||
panic("collections.Excepts: second must be a slice")
|
||||
}
|
||||
|
||||
valOfSecond := reflect.ValueOf(second)
|
||||
if valOfSecond.Len() == 0 {
|
||||
if len(second) == 0 {
|
||||
return CloneSlice(first)
|
||||
}
|
||||
|
||||
result := reflect.New(reflect.SliceOf(typeOfFirst.Elem())).Elem()
|
||||
for i := 0; i < valOfFirst.Len(); i++ {
|
||||
s := valOfFirst.Index(i).Interface()
|
||||
result := make([]T, 0)
|
||||
for _, s := range first {
|
||||
if i, _ := TwowaySearch(second, s, fn); i < 0 {
|
||||
result = reflect.Append(result, reflect.ValueOf(s))
|
||||
result = append(result, s)
|
||||
}
|
||||
}
|
||||
|
||||
return result.Interface()
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersects Produces to intersect of two slice according to a comparer function.
|
||||
//
|
||||
// first: the first slice. MUST BE A SLICE.
|
||||
// second: the second slice. MUST BE A SLICE.
|
||||
// fn: the comparer function.
|
||||
// returns: to intersect of the two slices.
|
||||
func Intersects(first any, second any, fn Comparer) any {
|
||||
typeOfFirst := reflect.TypeOf(first)
|
||||
if typeOfFirst.Kind() != reflect.Slice {
|
||||
panic("collections.Intersects: first must be a slice")
|
||||
}
|
||||
valOfFirst := reflect.ValueOf(first)
|
||||
if valOfFirst.Len() == 0 {
|
||||
return MakeEmptySlice(typeOfFirst.Elem())
|
||||
// - first: the first slice. MUST BE A SLICE.
|
||||
// - second: the second slice. MUST BE A SLICE.
|
||||
// - fn: the comparer function.
|
||||
// - returns: to intersect of the two slices.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Output: []string{"a", "b"}
|
||||
// Intersects([]string{"a", "b", "c"}, []string{"a", "b"}, arrutil.ValueEqualsComparer)
|
||||
func Intersects[T any](first, second []T, fn Comparer[T]) []T {
|
||||
if len(first) == 0 || len(second) == 0 {
|
||||
return make([]T, 0)
|
||||
}
|
||||
|
||||
typeOfSecond := reflect.TypeOf(second)
|
||||
if typeOfSecond.Kind() != reflect.Slice {
|
||||
panic("collections.Intersects: second must be a slice")
|
||||
}
|
||||
|
||||
valOfSecond := reflect.ValueOf(second)
|
||||
if valOfSecond.Len() == 0 {
|
||||
return MakeEmptySlice(typeOfFirst.Elem())
|
||||
}
|
||||
|
||||
result := reflect.New(reflect.SliceOf(typeOfFirst.Elem())).Elem()
|
||||
for i := 0; i < valOfFirst.Len(); i++ {
|
||||
s := valOfFirst.Index(i).Interface()
|
||||
result := make([]T, 0)
|
||||
for _, s := range first {
|
||||
if i, _ := TwowaySearch(second, s, fn); i >= 0 {
|
||||
result = reflect.Append(result, reflect.ValueOf(s))
|
||||
result = append(result, s)
|
||||
}
|
||||
}
|
||||
|
||||
return result.Interface()
|
||||
return result
|
||||
}
|
||||
|
||||
// Union Produces the set union of two slice according to a comparer function
|
||||
//
|
||||
// first: the first slice. MUST BE A SLICE.
|
||||
// second: the second slice. MUST BE A SLICE.
|
||||
// fn: the comparer function.
|
||||
// returns: the union of the two slices.
|
||||
func Union(first, second any, fn Comparer) any {
|
||||
excepts := Excepts(second, first, fn)
|
||||
|
||||
typeOfFirst := reflect.TypeOf(first)
|
||||
if typeOfFirst.Kind() != reflect.Slice {
|
||||
panic("collections.Intersects: first must be a slice")
|
||||
}
|
||||
valOfFirst := reflect.ValueOf(first)
|
||||
if valOfFirst.Len() == 0 {
|
||||
// - first: the first slice. MUST BE A SLICE.
|
||||
// - second: the second slice. MUST BE A SLICE.
|
||||
// - fn: the comparer function.
|
||||
// - returns: the union of the two slices.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Output: []string{"a", "b", "c"}
|
||||
// sl := Union([]string{"a", "b", "c"}, []string{"a", "b"}, arrutil.ValueEqualsComparer)
|
||||
func Union[T any](first, second []T, fn Comparer[T]) []T {
|
||||
if len(first) == 0 {
|
||||
return CloneSlice(second)
|
||||
}
|
||||
|
||||
result := reflect.AppendSlice(reflect.New(reflect.SliceOf(typeOfFirst.Elem())).Elem(), valOfFirst)
|
||||
result = reflect.AppendSlice(result, reflect.ValueOf(excepts))
|
||||
return result.Interface()
|
||||
excepts := Excepts(second, first, fn)
|
||||
nt := make([]T, 0, len(first)+len(second))
|
||||
nt = append(nt, first...)
|
||||
return append(nt, excepts...)
|
||||
}
|
||||
|
||||
// Find Produces the struct/value of a slice according to a predicate function.
|
||||
// Find Produces the value of a slice according to a predicate function.
|
||||
//
|
||||
// source: the slice. MUST BE A SLICE.
|
||||
// fn: the predicate function.
|
||||
// returns: the struct/value of the slice.
|
||||
func Find(source any, fn Predicate) (any, error) {
|
||||
aType := reflect.TypeOf(source)
|
||||
if aType.Kind() != reflect.Slice {
|
||||
panic("collections.Find: source must be a slice")
|
||||
// - source: the slice. MUST BE A SLICE.
|
||||
// - fn: the predicate function.
|
||||
// - returns: the struct/value of the slice.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Output: "c"
|
||||
// val := Find([]string{"a", "b", "c"}, func(s string) bool {
|
||||
// return s == "c"
|
||||
// })
|
||||
func Find[T any](source []T, fn Predicate[T]) (v T, err error) {
|
||||
err = ErrElementNotFound
|
||||
if len(source) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
sourceVal := reflect.ValueOf(source)
|
||||
if sourceVal.Len() == 0 {
|
||||
return nil, errors.New(ErrElementNotFound)
|
||||
}
|
||||
|
||||
for i := 0; i < sourceVal.Len(); i++ {
|
||||
s := sourceVal.Index(i).Interface()
|
||||
for _, s := range source {
|
||||
if fn(s) {
|
||||
return s, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New(ErrElementNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
// FindOrDefault Produce the struct/value f a slice to a predicate function,
|
||||
// FindOrDefault Produce the value f a slice to a predicate function,
|
||||
// Produce default value when predicate function not found.
|
||||
//
|
||||
// source: the slice. MUST BE A SLICE.
|
||||
// fn: the predicate function.
|
||||
// defaultValue: the default value.
|
||||
// returns: the struct/value of the slice.
|
||||
func FindOrDefault(source any, fn Predicate, defaultValue any) any {
|
||||
// - source: the slice. MUST BE A SLICE.
|
||||
// - fn: the predicate function.
|
||||
// - defaultValue: the default value.
|
||||
// - returns: the value of the slice.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Output: "d"
|
||||
// val := FindOrDefault([]string{"a", "b", "c"}, func(s string) bool {
|
||||
// return s == "d"
|
||||
// }, "d")
|
||||
func FindOrDefault[T any](source []T, fn Predicate[T], defaultValue T) T {
|
||||
item, err := Find(source, fn)
|
||||
if err != nil {
|
||||
if err.Error() == ErrElementNotFound {
|
||||
return defaultValue
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
return item
|
||||
}
|
||||
@@ -354,53 +286,53 @@ func FindOrDefault(source any, fn Predicate, defaultValue any) any {
|
||||
// TakeWhile Produce the set of a slice according to a predicate function,
|
||||
// Produce empty slice when predicate function not matched.
|
||||
//
|
||||
// data: the slice. MUST BE A SLICE.
|
||||
// fn: the predicate function.
|
||||
// returns: the set of the slice.
|
||||
func TakeWhile(data any, fn Predicate) any {
|
||||
aType := reflect.TypeOf(data)
|
||||
if aType.Kind() != reflect.Slice {
|
||||
panic("collections.TakeWhile: data must be a slice")
|
||||
// - data: the slice. MUST BE A SLICE.
|
||||
// - fn: the predicate function.
|
||||
// - returns: the set of the slice.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Output: []string{"a", "b"}
|
||||
// sl := TakeWhile([]string{"a", "b", "c"}, func(s string) bool {
|
||||
// return s != "c"
|
||||
// })
|
||||
func TakeWhile[T any](data []T, fn Predicate[T]) []T {
|
||||
result := make([]T, 0)
|
||||
if len(data) == 0 {
|
||||
return result
|
||||
}
|
||||
|
||||
sourceVal := reflect.ValueOf(data)
|
||||
if sourceVal.Len() == 0 {
|
||||
return MakeEmptySlice(aType.Elem())
|
||||
}
|
||||
|
||||
result := reflect.New(reflect.SliceOf(aType.Elem())).Elem()
|
||||
for i := 0; i < sourceVal.Len(); i++ {
|
||||
s := sourceVal.Index(i).Interface()
|
||||
if fn(s) {
|
||||
result = reflect.Append(result, reflect.ValueOf(s))
|
||||
for _, v := range data {
|
||||
if fn(v) {
|
||||
result = append(result, v)
|
||||
}
|
||||
}
|
||||
return result.Interface()
|
||||
return result
|
||||
}
|
||||
|
||||
// ExceptWhile Produce the set of a slice except with a predicate function,
|
||||
// Produce original slice when predicate function not match.
|
||||
//
|
||||
// data: the slice. MUST BE A SLICE.
|
||||
// fn: the predicate function.
|
||||
// returns: the set of the slice.
|
||||
func ExceptWhile(data any, fn Predicate) any {
|
||||
aType := reflect.TypeOf(data)
|
||||
if aType.Kind() != reflect.Slice {
|
||||
panic("collections.ExceptWhile: data must be a slice")
|
||||
// - data: the slice. MUST BE A SLICE.
|
||||
// - fn: the predicate function.
|
||||
// - returns: the set of the slice.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Output: []string{"a", "b"}
|
||||
// sl := ExceptWhile([]string{"a", "b", "c"}, func(s string) bool {
|
||||
// return s == "c"
|
||||
// })
|
||||
func ExceptWhile[T any](data []T, fn Predicate[T]) []T {
|
||||
result := make([]T, 0)
|
||||
if len(data) == 0 {
|
||||
return result
|
||||
}
|
||||
|
||||
sourceVal := reflect.ValueOf(data)
|
||||
if sourceVal.Len() == 0 {
|
||||
return MakeEmptySlice(aType.Elem())
|
||||
}
|
||||
|
||||
result := reflect.New(reflect.SliceOf(aType.Elem())).Elem()
|
||||
for i := 0; i < sourceVal.Len(); i++ {
|
||||
s := sourceVal.Index(i).Interface()
|
||||
if !fn(s) {
|
||||
result = reflect.Append(result, reflect.ValueOf(s))
|
||||
for _, v := range data {
|
||||
if !fn(v) {
|
||||
result = append(result, v)
|
||||
}
|
||||
}
|
||||
return result.Interface()
|
||||
return result
|
||||
}
|
||||
|
||||
22
vendor/github.com/gookit/goutil/arrutil/collection_gte118.go
generated
vendored
22
vendor/github.com/gookit/goutil/arrutil/collection_gte118.go
generated
vendored
@@ -1,22 +0,0 @@
|
||||
package arrutil
|
||||
|
||||
// type MapFn func(obj T) (target V, find bool)
|
||||
|
||||
// Map a list to new list
|
||||
//
|
||||
// eg: mapping [object0{},object1{},...] to flatten list [object0.someKey, object1.someKey, ...]
|
||||
func Map[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V {
|
||||
flatArr := make([]V, 0, len(list))
|
||||
|
||||
for _, obj := range list {
|
||||
if target, ok := mapFn(obj); ok {
|
||||
flatArr = append(flatArr, target)
|
||||
}
|
||||
}
|
||||
return flatArr
|
||||
}
|
||||
|
||||
// Column alias of Map func
|
||||
func Column[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V {
|
||||
return Map(list, mapFn)
|
||||
}
|
||||
92
vendor/github.com/gookit/goutil/arrutil/convert.go
generated
vendored
92
vendor/github.com/gookit/goutil/arrutil/convert.go
generated
vendored
@@ -29,6 +29,29 @@ func StringsJoin(sep string, ss ...string) string {
|
||||
return strings.Join(ss, sep)
|
||||
}
|
||||
|
||||
// JoinTyped join typed []T slice to string.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// JoinTyped(",", 1,2,3) // "1,2,3"
|
||||
// JoinTyped(",", "a","b","c") // "a,b,c"
|
||||
// JoinTyped[any](",", "a",1,"c") // "a,1,c"
|
||||
func JoinTyped[T any](sep string, arr ...T) string {
|
||||
if arr == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var sb strings.Builder
|
||||
for i, v := range arr {
|
||||
if i > 0 {
|
||||
sb.WriteString(sep)
|
||||
}
|
||||
sb.WriteString(strutil.QuietString(v))
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// JoinSlice join []any slice to string.
|
||||
func JoinSlice(sep string, arr ...any) string {
|
||||
if arr == nil {
|
||||
@@ -47,9 +70,27 @@ func JoinSlice(sep string, arr ...any) string {
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* helper func for slices
|
||||
* convert func for ints
|
||||
*************************************************************/
|
||||
|
||||
// IntsToString convert []T to string
|
||||
func IntsToString[T comdef.Integer](ints []T) string {
|
||||
if len(ints) == 0 {
|
||||
return "[]"
|
||||
}
|
||||
|
||||
var sb strings.Builder
|
||||
sb.WriteByte('[')
|
||||
for i, v := range ints {
|
||||
if i > 0 {
|
||||
sb.WriteByte(',')
|
||||
}
|
||||
sb.WriteString(strconv.FormatInt(int64(v), 10))
|
||||
}
|
||||
sb.WriteByte(']')
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// ToInt64s convert any(allow: array,slice) to []int64
|
||||
func ToInt64s(arr any) (ret []int64, err error) {
|
||||
rv := reflect.ValueOf(arr)
|
||||
@@ -84,29 +125,9 @@ func SliceToInt64s(arr []any) []int64 {
|
||||
return i64s
|
||||
}
|
||||
|
||||
// StringsAsInts convert and ignore error
|
||||
func StringsAsInts(ss []string) []int {
|
||||
ints, _ := StringsTryInts(ss)
|
||||
return ints
|
||||
}
|
||||
|
||||
// StringsToInts string slice to int slice
|
||||
func StringsToInts(ss []string) (ints []int, err error) {
|
||||
return StringsTryInts(ss)
|
||||
}
|
||||
|
||||
// StringsTryInts string slice to int slice
|
||||
func StringsTryInts(ss []string) (ints []int, err error) {
|
||||
for _, str := range ss {
|
||||
iVal, err := strconv.Atoi(str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ints = append(ints, iVal)
|
||||
}
|
||||
return
|
||||
}
|
||||
/*************************************************************
|
||||
* convert func for anys
|
||||
*************************************************************/
|
||||
|
||||
// AnyToSlice convert any(allow: array,slice) to []any
|
||||
func AnyToSlice(sl any) (ls []any, err error) {
|
||||
@@ -136,15 +157,6 @@ func MustToStrings(arr any) []string {
|
||||
return ret
|
||||
}
|
||||
|
||||
// StringsToSlice convert []string to []any
|
||||
func StringsToSlice(ss []string) []any {
|
||||
args := make([]any, len(ss))
|
||||
for i, s := range ss {
|
||||
args[i] = s
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
// ToStrings convert any(allow: array,slice) to []string
|
||||
func ToStrings(arr any) (ret []string, err error) {
|
||||
rv := reflect.ValueOf(arr)
|
||||
@@ -168,16 +180,16 @@ func ToStrings(arr any) (ret []string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// SliceToStrings convert []any to []string
|
||||
// SliceToStrings safe convert []any to []string
|
||||
func SliceToStrings(arr []any) []string {
|
||||
return QuietStrings(arr)
|
||||
}
|
||||
|
||||
// QuietStrings convert []any to []string
|
||||
// QuietStrings safe convert []any to []string
|
||||
func QuietStrings(arr []any) []string {
|
||||
ss := make([]string, len(arr))
|
||||
for i, v := range arr {
|
||||
ss[i] = strutil.QuietString(v)
|
||||
ss[i] = strutil.SafeString(v)
|
||||
}
|
||||
return ss
|
||||
}
|
||||
@@ -219,8 +231,8 @@ func AnyToString(arr any) string {
|
||||
// SliceToString convert []any to string
|
||||
func SliceToString(arr ...any) string { return ToString(arr) }
|
||||
|
||||
// ToString simple and quickly convert []any to string
|
||||
func ToString(arr []any) string {
|
||||
// ToString simple and quickly convert []T to string
|
||||
func ToString[T any](arr []T) string {
|
||||
// like fmt.Println([]any(nil))
|
||||
if arr == nil {
|
||||
return "[]"
|
||||
@@ -233,14 +245,14 @@ func ToString(arr []any) string {
|
||||
if i > 0 {
|
||||
sb.WriteByte(',')
|
||||
}
|
||||
sb.WriteString(strutil.QuietString(v))
|
||||
sb.WriteString(strutil.SafeString(v))
|
||||
}
|
||||
|
||||
sb.WriteByte(']')
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// CombineToMap combine two slice to map[K]V.
|
||||
// CombineToMap combine []K and []V slice to map[K]V.
|
||||
//
|
||||
// If keys length is greater than values, the extra keys will be ignored.
|
||||
func CombineToMap[K comdef.SortedType, V any](keys []K, values []V) map[K]V {
|
||||
|
||||
64
vendor/github.com/gookit/goutil/arrutil/enum.go
generated
vendored
64
vendor/github.com/gookit/goutil/arrutil/enum.go
generated
vendored
@@ -1,64 +0,0 @@
|
||||
package arrutil
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Ints type
|
||||
type Ints []int
|
||||
|
||||
// String to string
|
||||
func (is Ints) String() string {
|
||||
ss := make([]string, len(is))
|
||||
for i, iv := range is {
|
||||
ss[i] = strconv.Itoa(iv)
|
||||
}
|
||||
return strings.Join(ss, ",")
|
||||
}
|
||||
|
||||
// Has given element
|
||||
func (is Ints) Has(i int) bool {
|
||||
for _, iv := range is {
|
||||
if i == iv {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Strings type
|
||||
type Strings []string
|
||||
|
||||
// String to string
|
||||
func (ss Strings) String() string {
|
||||
return strings.Join(ss, ",")
|
||||
}
|
||||
|
||||
// Join to string
|
||||
func (ss Strings) Join(sep string) string {
|
||||
return strings.Join(ss, sep)
|
||||
}
|
||||
|
||||
// Has given element
|
||||
func (ss Strings) Has(sub string) bool {
|
||||
return ss.Contains(sub)
|
||||
}
|
||||
|
||||
// Contains given element
|
||||
func (ss Strings) Contains(sub string) bool {
|
||||
for _, s := range ss {
|
||||
if s == sub {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// First element value.
|
||||
func (ss Strings) First() string {
|
||||
if len(ss) > 0 {
|
||||
return ss[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
14
vendor/github.com/gookit/goutil/arrutil/format.go
generated
vendored
14
vendor/github.com/gookit/goutil/arrutil/format.go
generated
vendored
@@ -15,7 +15,7 @@ type ArrFormatter struct {
|
||||
Prefix string
|
||||
// Indent string for format each element
|
||||
Indent string
|
||||
// ClosePrefix string for last "]"
|
||||
// ClosePrefix on before end char: ]
|
||||
ClosePrefix string
|
||||
}
|
||||
|
||||
@@ -23,10 +23,14 @@ type ArrFormatter struct {
|
||||
func NewFormatter(arr any) *ArrFormatter {
|
||||
f := &ArrFormatter{}
|
||||
f.Src = arr
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// FormatIndent array data to string.
|
||||
func FormatIndent(arr any, indent string) string {
|
||||
return NewFormatter(arr).WithIndent(indent).Format()
|
||||
}
|
||||
|
||||
// WithFn for config self
|
||||
func (f *ArrFormatter) WithFn(fn func(f *ArrFormatter)) *ArrFormatter {
|
||||
fn(f)
|
||||
@@ -47,7 +51,6 @@ func (f *ArrFormatter) FormatTo(w io.Writer) {
|
||||
|
||||
// Format to string
|
||||
func (f *ArrFormatter) String() string {
|
||||
f.Format()
|
||||
return f.Format()
|
||||
}
|
||||
|
||||
@@ -118,8 +121,3 @@ func (f *ArrFormatter) doFormat() {
|
||||
}
|
||||
writer.WriteByte(']')
|
||||
}
|
||||
|
||||
// FormatIndent array data to string.
|
||||
func FormatIndent(arr any, indent string) string {
|
||||
return NewFormatter(arr).WithIndent(indent).Format()
|
||||
}
|
||||
|
||||
216
vendor/github.com/gookit/goutil/arrutil/list.go
generated
vendored
Normal file
216
vendor/github.com/gookit/goutil/arrutil/list.go
generated
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
package arrutil
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
)
|
||||
|
||||
// Ints type
|
||||
type Ints[T comdef.Integer] []T
|
||||
|
||||
// String to string
|
||||
func (is Ints[T]) String() string {
|
||||
return ToString(is)
|
||||
}
|
||||
|
||||
// Has given element
|
||||
func (is Ints[T]) Has(i T) bool {
|
||||
for _, iv := range is {
|
||||
if i == iv {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// First element value.
|
||||
func (is Ints[T]) First(defVal ...T) T {
|
||||
if len(is) > 0 {
|
||||
return is[0]
|
||||
}
|
||||
|
||||
if len(defVal) > 0 {
|
||||
return defVal[0]
|
||||
}
|
||||
panic("empty integer slice")
|
||||
}
|
||||
|
||||
// Last element value.
|
||||
func (is Ints[T]) Last(defVal ...T) T {
|
||||
if len(is) > 0 {
|
||||
return is[len(is)-1]
|
||||
}
|
||||
|
||||
if len(defVal) > 0 {
|
||||
return defVal[0]
|
||||
}
|
||||
panic("empty integer slice")
|
||||
}
|
||||
|
||||
// Sort the int slice
|
||||
func (is Ints[T]) Sort() {
|
||||
sort.Sort(is)
|
||||
}
|
||||
|
||||
// Len get length
|
||||
func (is Ints[T]) Len() int {
|
||||
return len(is)
|
||||
}
|
||||
|
||||
// Less compare two elements
|
||||
func (is Ints[T]) Less(i, j int) bool {
|
||||
return is[i] < is[j]
|
||||
}
|
||||
|
||||
// Swap elements by indexes
|
||||
func (is Ints[T]) Swap(i, j int) {
|
||||
is[i], is[j] = is[j], is[i]
|
||||
}
|
||||
|
||||
// Strings type
|
||||
type Strings []string
|
||||
|
||||
// String to string
|
||||
func (ss Strings) String() string {
|
||||
return strings.Join(ss, ",")
|
||||
}
|
||||
|
||||
// Join to string
|
||||
func (ss Strings) Join(sep string) string {
|
||||
return strings.Join(ss, sep)
|
||||
}
|
||||
|
||||
// Has given element
|
||||
func (ss Strings) Has(sub string) bool {
|
||||
return ss.Contains(sub)
|
||||
}
|
||||
|
||||
// Contains given element
|
||||
func (ss Strings) Contains(sub string) bool {
|
||||
for _, s := range ss {
|
||||
if s == sub {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// First element value.
|
||||
func (ss Strings) First(defVal ...string) string {
|
||||
if len(ss) > 0 {
|
||||
return ss[0]
|
||||
}
|
||||
|
||||
if len(defVal) > 0 {
|
||||
return defVal[0]
|
||||
}
|
||||
panic("empty string list")
|
||||
}
|
||||
|
||||
// Last element value.
|
||||
func (ss Strings) Last(defVal ...string) string {
|
||||
if len(ss) > 0 {
|
||||
return ss[len(ss)-1]
|
||||
}
|
||||
|
||||
if len(defVal) > 0 {
|
||||
return defVal[0]
|
||||
}
|
||||
panic("empty string list")
|
||||
}
|
||||
|
||||
// Sort the string slice
|
||||
func (ss Strings) Sort() {
|
||||
sort.Strings(ss)
|
||||
}
|
||||
|
||||
// SortedList definition for compared type
|
||||
type SortedList[T comdef.Compared] []T
|
||||
|
||||
// Len get length
|
||||
func (ls SortedList[T]) Len() int {
|
||||
return len(ls)
|
||||
}
|
||||
|
||||
// Less compare two elements
|
||||
func (ls SortedList[T]) Less(i, j int) bool {
|
||||
return ls[i] < ls[j]
|
||||
}
|
||||
|
||||
// Swap elements by indexes
|
||||
func (ls SortedList[T]) Swap(i, j int) {
|
||||
ls[i], ls[j] = ls[j], ls[i]
|
||||
}
|
||||
|
||||
// IsEmpty check
|
||||
func (ls SortedList[T]) IsEmpty() bool {
|
||||
return len(ls) == 0
|
||||
}
|
||||
|
||||
// String to string
|
||||
func (ls SortedList[T]) String() string {
|
||||
return ToString(ls)
|
||||
}
|
||||
|
||||
// Has given element
|
||||
func (ls SortedList[T]) Has(el T) bool {
|
||||
return ls.Contains(el)
|
||||
}
|
||||
|
||||
// Contains given element
|
||||
func (ls SortedList[T]) Contains(el T) bool {
|
||||
for _, v := range ls {
|
||||
if v == el {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// First element value.
|
||||
func (ls SortedList[T]) First(defVal ...T) T {
|
||||
if len(ls) > 0 {
|
||||
return ls[0]
|
||||
}
|
||||
|
||||
if len(defVal) > 0 {
|
||||
return defVal[0]
|
||||
}
|
||||
panic("empty list")
|
||||
}
|
||||
|
||||
// Last element value.
|
||||
func (ls SortedList[T]) Last(defVal ...T) T {
|
||||
if ln := len(ls); ln > 0 {
|
||||
return ls[ln-1]
|
||||
}
|
||||
|
||||
if len(defVal) > 0 {
|
||||
return defVal[0]
|
||||
}
|
||||
panic("empty list")
|
||||
}
|
||||
|
||||
// Remove given element
|
||||
func (ls SortedList[T]) Remove(el T) SortedList[T] {
|
||||
return Filter(ls, func(v T) bool {
|
||||
return v != el
|
||||
})
|
||||
}
|
||||
|
||||
// Filter the slice, default will filter zero value.
|
||||
func (ls SortedList[T]) Filter(filter ...comdef.MatchFunc[T]) SortedList[T] {
|
||||
return Filter(ls, filter...)
|
||||
}
|
||||
|
||||
// Map the slice to new slice. TODO syntax ERROR: Method cannot have type parameters
|
||||
// func (ls SortedList[T]) Map[V any](mapFn MapFn[T, V]) SortedList[V] {
|
||||
// return Map(ls, mapFn)
|
||||
// }
|
||||
|
||||
// Sort the slice
|
||||
func (ls SortedList[T]) Sort() {
|
||||
sort.Sort(ls)
|
||||
}
|
||||
102
vendor/github.com/gookit/goutil/arrutil/process.go
generated
vendored
Normal file
102
vendor/github.com/gookit/goutil/arrutil/process.go
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
package arrutil
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
)
|
||||
|
||||
// Reverse any T slice.
|
||||
//
|
||||
// eg: []string{"site", "user", "info", "0"} -> []string{"0", "info", "user", "site"}
|
||||
func Reverse[T any](ls []T) {
|
||||
ln := len(ls)
|
||||
for i := 0; i < ln/2; i++ {
|
||||
li := ln - i - 1
|
||||
ls[i], ls[li] = ls[li], ls[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Remove give element from slice []T.
|
||||
//
|
||||
// eg: []string{"site", "user", "info", "0"} -> []string{"site", "user", "info"}
|
||||
func Remove[T comdef.Compared](ls []T, val T) []T {
|
||||
return Filter(ls, func(el T) bool {
|
||||
return el != val
|
||||
})
|
||||
}
|
||||
|
||||
// Filter given slice, default will filter zero value.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// // output: [a, b]
|
||||
// ss := arrutil.Filter([]string{"a", "", "b", ""})
|
||||
func Filter[T any](ls []T, filter ...comdef.MatchFunc[T]) []T {
|
||||
var fn comdef.MatchFunc[T]
|
||||
if len(filter) > 0 && filter[0] != nil {
|
||||
fn = filter[0]
|
||||
} else {
|
||||
fn = func(el T) bool {
|
||||
return !reflect.ValueOf(el).IsZero()
|
||||
}
|
||||
}
|
||||
|
||||
newLs := make([]T, 0, len(ls))
|
||||
for _, el := range ls {
|
||||
if fn(el) {
|
||||
newLs = append(newLs, el)
|
||||
}
|
||||
}
|
||||
return newLs
|
||||
}
|
||||
|
||||
// MapFn map handle function type.
|
||||
type MapFn[T any, V any] func(input T) (target V, find bool)
|
||||
|
||||
// Map a list to new list
|
||||
//
|
||||
// eg: mapping [object0{},object1{},...] to flatten list [object0.someKey, object1.someKey, ...]
|
||||
func Map[T any, V any](list []T, mapFn MapFn[T, V]) []V {
|
||||
flatArr := make([]V, 0, len(list))
|
||||
|
||||
for _, obj := range list {
|
||||
if target, ok := mapFn(obj); ok {
|
||||
flatArr = append(flatArr, target)
|
||||
}
|
||||
}
|
||||
return flatArr
|
||||
}
|
||||
|
||||
// Column alias of Map func
|
||||
func Column[T any, V any](list []T, mapFn func(obj T) (val V, find bool)) []V {
|
||||
return Map(list, mapFn)
|
||||
}
|
||||
|
||||
// Unique value in the given slice data.
|
||||
func Unique[T ~string | comdef.XintOrFloat](list []T) []T {
|
||||
if len(list) < 2 {
|
||||
return list
|
||||
}
|
||||
|
||||
valMap := make(map[T]struct{}, len(list))
|
||||
uniArr := make([]T, 0, len(list))
|
||||
|
||||
for _, t := range list {
|
||||
if _, ok := valMap[t]; !ok {
|
||||
valMap[t] = struct{}{}
|
||||
uniArr = append(uniArr, t)
|
||||
}
|
||||
}
|
||||
return uniArr
|
||||
}
|
||||
|
||||
// IndexOf value in given slice.
|
||||
func IndexOf[T ~string | comdef.XintOrFloat](val T, list []T) int {
|
||||
for i, v := range list {
|
||||
if v == val {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
137
vendor/github.com/gookit/goutil/arrutil/strings.go
generated
vendored
Normal file
137
vendor/github.com/gookit/goutil/arrutil/strings.go
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
package arrutil
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
)
|
||||
|
||||
// StringsToAnys convert []string to []any
|
||||
func StringsToAnys(ss []string) []any {
|
||||
args := make([]any, len(ss))
|
||||
for i, s := range ss {
|
||||
args[i] = s
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
// StringsToSlice convert []string to []any. alias of StringsToAnys()
|
||||
func StringsToSlice(ss []string) []any {
|
||||
return StringsToAnys(ss)
|
||||
}
|
||||
|
||||
// StringsAsInts convert and ignore error
|
||||
func StringsAsInts(ss []string) []int {
|
||||
ints, _ := StringsTryInts(ss)
|
||||
return ints
|
||||
}
|
||||
|
||||
// StringsToInts string slice to int slice
|
||||
func StringsToInts(ss []string) (ints []int, err error) {
|
||||
return StringsTryInts(ss)
|
||||
}
|
||||
|
||||
// StringsTryInts string slice to int slice
|
||||
func StringsTryInts(ss []string) (ints []int, err error) {
|
||||
for _, str := range ss {
|
||||
iVal, err := strconv.Atoi(str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ints = append(ints, iVal)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// StringsUnique unique string slice
|
||||
func StringsUnique(ss []string) []string {
|
||||
var unique []string
|
||||
for _, s := range ss {
|
||||
if !StringsContains(unique, s) {
|
||||
unique = append(unique, s)
|
||||
}
|
||||
}
|
||||
return unique
|
||||
}
|
||||
|
||||
// StringsContains check string slice contains string
|
||||
func StringsContains(ss []string, s string) bool {
|
||||
for _, v := range ss {
|
||||
if v == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// StringsRemove value form a string slice
|
||||
func StringsRemove(ss []string, s string) []string {
|
||||
return StringsFilter(ss, func(el string) bool {
|
||||
return s != el
|
||||
})
|
||||
}
|
||||
|
||||
// StringsFilter given strings, default will filter emtpy string.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// // output: [a, b]
|
||||
// ss := arrutil.StringsFilter([]string{"a", "", "b", ""})
|
||||
func StringsFilter(ss []string, filter ...comdef.StringMatchFunc) []string {
|
||||
var fn comdef.StringMatchFunc
|
||||
if len(filter) > 0 && filter[0] != nil {
|
||||
fn = filter[0]
|
||||
} else {
|
||||
fn = func(s string) bool {
|
||||
return s != ""
|
||||
}
|
||||
}
|
||||
|
||||
ns := make([]string, 0, len(ss))
|
||||
for _, s := range ss {
|
||||
if fn(s) {
|
||||
ns = append(ns, s)
|
||||
}
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
// StringsMap handle each string item, map to new strings
|
||||
func StringsMap(ss []string, mapFn func(s string) string) []string {
|
||||
ns := make([]string, 0, len(ss))
|
||||
for _, s := range ss {
|
||||
ns = append(ns, mapFn(s))
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
// TrimStrings trim string slice item.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// // output: [a, b, c]
|
||||
// ss := arrutil.TrimStrings([]string{",a", "b.", ",.c,"}, ",.")
|
||||
func TrimStrings(ss []string, cutSet ...string) []string {
|
||||
cutSetLn := len(cutSet)
|
||||
hasCutSet := cutSetLn > 0 && cutSet[0] != ""
|
||||
|
||||
var trimSet string
|
||||
if hasCutSet {
|
||||
trimSet = cutSet[0]
|
||||
}
|
||||
if cutSetLn > 1 {
|
||||
trimSet = strings.Join(cutSet, "")
|
||||
}
|
||||
|
||||
ns := make([]string, 0, len(ss))
|
||||
for _, str := range ss {
|
||||
if hasCutSet {
|
||||
ns = append(ns, strings.Trim(str, trimSet))
|
||||
} else {
|
||||
ns = append(ns, strings.TrimSpace(str))
|
||||
}
|
||||
}
|
||||
return ns
|
||||
}
|
||||
@@ -1,13 +1,52 @@
|
||||
// Package basefn provide some no-dependents util functions
|
||||
package basefn
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Panicf format panic message use fmt.Sprintf
|
||||
func Panicf(format string, v ...any) {
|
||||
panic(fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// PanicIf if cond = true, panics with error message
|
||||
func PanicIf(cond bool, fmtAndArgs ...any) {
|
||||
if cond {
|
||||
panic(errors.New(formatWithArgs(fmtAndArgs)))
|
||||
}
|
||||
}
|
||||
|
||||
func formatWithArgs(fmtAndArgs []any) string {
|
||||
ln := len(fmtAndArgs)
|
||||
if ln == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
first := fmtAndArgs[0]
|
||||
|
||||
if ln == 1 {
|
||||
if msgAsStr, ok := first.(string); ok {
|
||||
return msgAsStr
|
||||
}
|
||||
return fmt.Sprintf("%+v", first)
|
||||
}
|
||||
|
||||
// is template string.
|
||||
if tplStr, ok := first.(string); ok {
|
||||
return fmt.Sprintf(tplStr, fmtAndArgs[1:]...)
|
||||
}
|
||||
return fmt.Sprint(fmtAndArgs...)
|
||||
}
|
||||
|
||||
// PanicErr panics if error is not empty
|
||||
func PanicErr(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// MustOK if error is not empty, will panic
|
||||
func MustOK(err error) {
|
||||
if err != nil {
|
||||
7
vendor/github.com/gookit/goutil/byteutil/buffer.go
generated
vendored
7
vendor/github.com/gookit/goutil/byteutil/buffer.go
generated
vendored
@@ -6,11 +6,13 @@ import (
|
||||
)
|
||||
|
||||
// Buffer wrap and extends the bytes.Buffer, add some useful methods
|
||||
// and implements the io.Writer, io.Closer and stdio.Flusher interfaces
|
||||
type Buffer struct {
|
||||
bytes.Buffer
|
||||
// custom error for testing
|
||||
CloseErr error
|
||||
FlushErr error
|
||||
SyncErr error
|
||||
}
|
||||
|
||||
// NewBuffer instance
|
||||
@@ -117,3 +119,8 @@ func (b *Buffer) Close() error {
|
||||
func (b *Buffer) Flush() error {
|
||||
return b.FlushErr
|
||||
}
|
||||
|
||||
// Sync anf flush buffer
|
||||
func (b *Buffer) Sync() error {
|
||||
return b.SyncErr
|
||||
}
|
||||
|
||||
71
vendor/github.com/gookit/goutil/byteutil/byteutil.go
generated
vendored
71
vendor/github.com/gookit/goutil/byteutil/byteutil.go
generated
vendored
@@ -1,14 +1,40 @@
|
||||
// Package byteutil provides some useful functions for byte slice.
|
||||
package byteutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Md5 Generate a 32-bit md5 bytes
|
||||
func Md5(src any) []byte {
|
||||
h := md5.New()
|
||||
|
||||
switch val := src.(type) {
|
||||
case []byte:
|
||||
h.Write(val)
|
||||
case string:
|
||||
h.Write([]byte(val))
|
||||
default:
|
||||
h.Write([]byte(fmt.Sprint(src)))
|
||||
}
|
||||
|
||||
bs := h.Sum(nil) // cap(bs) == 16
|
||||
dst := make([]byte, hex.EncodedLen(len(bs)))
|
||||
hex.Encode(dst, bs)
|
||||
return dst
|
||||
}
|
||||
|
||||
// ShortMd5 Generate a 16-bit md5 bytes. remove first 8 and last 8 bytes from 32-bit md5.
|
||||
func ShortMd5(src any) []byte {
|
||||
return Md5(src)[8:24]
|
||||
}
|
||||
|
||||
// Random bytes generate
|
||||
func Random(length int) ([]byte, error) {
|
||||
b := make([]byte, length)
|
||||
@@ -27,32 +53,6 @@ func FirstLine(bs []byte) []byte {
|
||||
return bs
|
||||
}
|
||||
|
||||
// StrOrErr convert to string, return empty string on error.
|
||||
func StrOrErr(bs []byte, err error) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(bs), err
|
||||
}
|
||||
|
||||
// SafeString convert to string, return empty string on error.
|
||||
func SafeString(bs []byte, err error) string {
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(bs)
|
||||
}
|
||||
|
||||
// String unsafe convert bytes to string
|
||||
func String(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
// ToString convert bytes to string
|
||||
func ToString(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
// AppendAny append any value to byte slice
|
||||
func AppendAny(dst []byte, v any) []byte {
|
||||
if v == nil {
|
||||
@@ -104,12 +104,19 @@ func AppendAny(dst []byte, v any) []byte {
|
||||
return dst
|
||||
}
|
||||
|
||||
// Cut bytes. like the strings.Cut()
|
||||
// Cut bytes by one byte char. like bytes.Cut(), but sep is byte.
|
||||
func Cut(bs []byte, sep byte) (before, after []byte, found bool) {
|
||||
if i := bytes.IndexByte(bs, sep); i >= 0 {
|
||||
return bs[:i], bs[i+1:], true
|
||||
}
|
||||
return bytes.Cut(bs, []byte{sep})
|
||||
}
|
||||
|
||||
before = bs
|
||||
// SafeCut bytes by one byte char. always return before and after
|
||||
func SafeCut(bs []byte, sep byte) (before, after []byte) {
|
||||
before, after, _ = bytes.Cut(bs, []byte{sep})
|
||||
return
|
||||
}
|
||||
|
||||
// SafeCuts bytes by sub bytes. like the bytes.Cut(), but always return before and after
|
||||
func SafeCuts(bs []byte, sep []byte) (before, after []byte) {
|
||||
before, after, _ = bytes.Cut(bs, sep)
|
||||
return
|
||||
}
|
||||
|
||||
19
vendor/github.com/gookit/goutil/byteutil/bytex.go
generated
vendored
19
vendor/github.com/gookit/goutil/byteutil/bytex.go
generated
vendored
@@ -1,19 +0,0 @@
|
||||
// Package byteutil Provide some bytes utils functions or structs
|
||||
package byteutil
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Md5 Generate a 32-bit md5 bytes
|
||||
func Md5(src any) []byte {
|
||||
h := md5.New()
|
||||
|
||||
if s, ok := src.(string); ok {
|
||||
h.Write([]byte(s))
|
||||
} else {
|
||||
h.Write([]byte(fmt.Sprint(src)))
|
||||
}
|
||||
return h.Sum(nil)
|
||||
}
|
||||
109
vendor/github.com/gookit/goutil/byteutil/conv.go
generated
vendored
Normal file
109
vendor/github.com/gookit/goutil/byteutil/conv.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
package byteutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
)
|
||||
|
||||
// StrOrErr convert to string, return empty string on error.
|
||||
func StrOrErr(bs []byte, err error) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(bs), err
|
||||
}
|
||||
|
||||
// SafeString convert to string, return empty string on error.
|
||||
func SafeString(bs []byte, err error) string {
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(bs)
|
||||
}
|
||||
|
||||
// String unsafe convert bytes to string
|
||||
func String(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
// ToString convert bytes to string
|
||||
func ToString(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
// ToBytes convert any value to []byte. return error on convert failed.
|
||||
func ToBytes(v any) ([]byte, error) {
|
||||
return ToBytesWithFunc(v, nil)
|
||||
}
|
||||
|
||||
// SafeBytes convert any value to []byte. use fmt.Sprint() on convert failed.
|
||||
func SafeBytes(v any) []byte {
|
||||
bs, _ := ToBytesWithFunc(v, func(v any) ([]byte, error) {
|
||||
return []byte(fmt.Sprint(v)), nil
|
||||
})
|
||||
return bs
|
||||
}
|
||||
|
||||
// ToBytesFunc convert any value to []byte
|
||||
type ToBytesFunc = func(v any) ([]byte, error)
|
||||
|
||||
// ToBytesWithFunc convert any value to []byte with custom fallback func.
|
||||
//
|
||||
// refer the strutil.ToStringWithFunc
|
||||
//
|
||||
// On not convert:
|
||||
// - If usrFn is nil, will return comdef.ErrConvType.
|
||||
// - If usrFn is not nil, will call it to convert.
|
||||
func ToBytesWithFunc(v any, usrFn ToBytesFunc) ([]byte, error) {
|
||||
if v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
switch val := v.(type) {
|
||||
case []byte:
|
||||
return val, nil
|
||||
case string:
|
||||
return []byte(val), nil
|
||||
case int:
|
||||
return []byte(strconv.Itoa(val)), nil
|
||||
case int8:
|
||||
return []byte(strconv.Itoa(int(val))), nil
|
||||
case int16:
|
||||
return []byte(strconv.Itoa(int(val))), nil
|
||||
case int32: // same as `rune`
|
||||
return []byte(strconv.Itoa(int(val))), nil
|
||||
case int64:
|
||||
return []byte(strconv.FormatInt(val, 10)), nil
|
||||
case uint:
|
||||
return []byte(strconv.FormatUint(uint64(val), 10)), nil
|
||||
case uint8:
|
||||
return []byte(strconv.FormatUint(uint64(val), 10)), nil
|
||||
case uint16:
|
||||
return []byte(strconv.FormatUint(uint64(val), 10)), nil
|
||||
case uint32:
|
||||
return []byte(strconv.FormatUint(uint64(val), 10)), nil
|
||||
case uint64:
|
||||
return []byte(strconv.FormatUint(val, 10)), nil
|
||||
case float32:
|
||||
return []byte(strconv.FormatFloat(float64(val), 'f', -1, 32)), nil
|
||||
case float64:
|
||||
return []byte(strconv.FormatFloat(val, 'f', -1, 64)), nil
|
||||
case bool:
|
||||
return []byte(strconv.FormatBool(val)), nil
|
||||
case time.Duration:
|
||||
return []byte(strconv.FormatInt(int64(val), 10)), nil
|
||||
case fmt.Stringer:
|
||||
return []byte(val.String()), nil
|
||||
case error:
|
||||
return []byte(val.Error()), nil
|
||||
default:
|
||||
if usrFn == nil {
|
||||
return nil, comdef.ErrConvType
|
||||
}
|
||||
return usrFn(val)
|
||||
}
|
||||
}
|
||||
12
vendor/github.com/gookit/goutil/byteutil/encoder.go
generated
vendored
12
vendor/github.com/gookit/goutil/byteutil/encoder.go
generated
vendored
@@ -5,6 +5,12 @@ import (
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
// BytesEncodeFunc type
|
||||
type BytesEncodeFunc func(src []byte) []byte
|
||||
|
||||
// BytesDecodeFunc type
|
||||
type BytesDecodeFunc func(src []byte) ([]byte, error)
|
||||
|
||||
// BytesEncoder interface
|
||||
type BytesEncoder interface {
|
||||
Encode(src []byte) []byte
|
||||
@@ -13,12 +19,12 @@ type BytesEncoder interface {
|
||||
|
||||
// StdEncoder implement the BytesEncoder
|
||||
type StdEncoder struct {
|
||||
encodeFn func(src []byte) []byte
|
||||
decodeFn func(src []byte) ([]byte, error)
|
||||
encodeFn BytesEncodeFunc
|
||||
decodeFn BytesDecodeFunc
|
||||
}
|
||||
|
||||
// NewStdEncoder instance
|
||||
func NewStdEncoder(encFn func(src []byte) []byte, decFn func(src []byte) ([]byte, error)) *StdEncoder {
|
||||
func NewStdEncoder(encFn BytesEncodeFunc, decFn BytesDecodeFunc) *StdEncoder {
|
||||
return &StdEncoder{
|
||||
encodeFn: encFn,
|
||||
decodeFn: decFn,
|
||||
|
||||
11
vendor/github.com/gookit/goutil/byteutil/pool.go
generated
vendored
11
vendor/github.com/gookit/goutil/byteutil/pool.go
generated
vendored
@@ -13,14 +13,14 @@ package byteutil
|
||||
// from https://github.com/minio/minio/blob/master/internal/bpool/bpool.go
|
||||
type ChanPool struct {
|
||||
c chan []byte
|
||||
w int
|
||||
wcap int
|
||||
w int // init byte width
|
||||
wcap int // set byte cap
|
||||
}
|
||||
|
||||
// NewChanPool instance
|
||||
func NewChanPool(maxSize int, width int, capWidth int) *ChanPool {
|
||||
func NewChanPool(chSize int, width int, capWidth int) *ChanPool {
|
||||
return &ChanPool{
|
||||
c: make(chan []byte, maxSize),
|
||||
c: make(chan []byte, chSize),
|
||||
w: width,
|
||||
wcap: capWidth,
|
||||
}
|
||||
@@ -30,8 +30,7 @@ func NewChanPool(maxSize int, width int, capWidth int) *ChanPool {
|
||||
// available in the pool.
|
||||
func (bp *ChanPool) Get() (b []byte) {
|
||||
select {
|
||||
case b = <-bp.c:
|
||||
// reuse existing buffer
|
||||
case b = <-bp.c: // reuse existing buffer
|
||||
default:
|
||||
// create new buffer
|
||||
if bp.wcap > 0 {
|
||||
|
||||
9
vendor/github.com/gookit/goutil/check.go
generated
vendored
9
vendor/github.com/gookit/goutil/check.go
generated
vendored
@@ -3,8 +3,8 @@ package goutil
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/gookit/goutil/internal/checkfn"
|
||||
"github.com/gookit/goutil/reflects"
|
||||
"github.com/gookit/goutil/stdutil"
|
||||
)
|
||||
|
||||
// IsNil value check
|
||||
@@ -15,6 +15,9 @@ func IsNil(v any) bool {
|
||||
return reflects.IsNil(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
// IsZero value check, alias of the IsEmpty()
|
||||
var IsZero = IsEmpty
|
||||
|
||||
// IsEmpty value check
|
||||
func IsEmpty(v any) bool {
|
||||
if v == nil {
|
||||
@@ -55,7 +58,7 @@ func IsEqual(src, dst any) bool {
|
||||
// string - check sub-string exists
|
||||
// array,slice - check sub-element exists
|
||||
func Contains(data, elem any) bool {
|
||||
_, found := stdutil.CheckContains(data, elem)
|
||||
_, found := checkfn.Contains(data, elem)
|
||||
return found
|
||||
}
|
||||
|
||||
@@ -67,6 +70,6 @@ func Contains(data, elem any) bool {
|
||||
// string - check sub-string exists
|
||||
// array,slice - check sub-element exists
|
||||
func IsContains(data, elem any) bool {
|
||||
_, found := stdutil.CheckContains(data, elem)
|
||||
_, found := checkfn.Contains(data, elem)
|
||||
return found
|
||||
}
|
||||
|
||||
4
vendor/github.com/gookit/goutil/cliutil/cmdline/builder.go
generated
vendored
4
vendor/github.com/gookit/goutil/cliutil/cmdline/builder.go
generated
vendored
@@ -55,13 +55,13 @@ func (b *LineBuilder) WriteString(a string) (int, error) {
|
||||
if pos := strings.IndexByte(a, '"'); pos > -1 {
|
||||
quote = '\''
|
||||
// fix: a = `--pretty=format:"one two three"`
|
||||
if pos > 0 && '"' == a[len(a)-1] {
|
||||
if pos > 0 && a[len(a)-1] == '"' {
|
||||
quote = 0
|
||||
}
|
||||
} else if pos := strings.IndexByte(a, '\''); pos > -1 {
|
||||
quote = '"'
|
||||
// fix: a = "--pretty=format:'one two three'"
|
||||
if pos > 0 && '\'' == a[len(a)-1] {
|
||||
if pos > 0 && a[len(a)-1] == '\'' {
|
||||
quote = 0
|
||||
}
|
||||
} else if a == "" || strings.ContainsRune(a, ' ') {
|
||||
|
||||
4
vendor/github.com/gookit/goutil/cliutil/cmdline/parser.go
generated
vendored
4
vendor/github.com/gookit/goutil/cliutil/cmdline/parser.go
generated
vendored
@@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
"github.com/gookit/goutil/internal/varexpr"
|
||||
"github.com/gookit/goutil/strutil"
|
||||
)
|
||||
|
||||
@@ -86,7 +86,7 @@ func (p *LineParser) Parse() []string {
|
||||
|
||||
// enable parse Env var
|
||||
if p.ParseEnv {
|
||||
p.Line = comfunc.ParseEnvVar(p.Line, nil)
|
||||
p.Line = varexpr.SafeParse(p.Line)
|
||||
}
|
||||
|
||||
p.nodes = strings.Split(p.Line, " ")
|
||||
|
||||
44
vendor/github.com/gookit/goutil/comdef/comdef.go
generated
vendored
44
vendor/github.com/gookit/goutil/comdef/comdef.go
generated
vendored
@@ -1,38 +1,6 @@
|
||||
// Package comdef provide some common type or constant definitions
|
||||
package comdef
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// ByteStringWriter interface
|
||||
type ByteStringWriter interface {
|
||||
io.Writer
|
||||
io.ByteWriter
|
||||
io.StringWriter
|
||||
fmt.Stringer
|
||||
}
|
||||
|
||||
// StringWriteStringer interface
|
||||
type StringWriteStringer interface {
|
||||
io.StringWriter
|
||||
fmt.Stringer
|
||||
}
|
||||
|
||||
// StringMatcher interface
|
||||
type StringMatcher interface {
|
||||
Match(s string) bool
|
||||
}
|
||||
|
||||
// StringMatchFunc definition
|
||||
type StringMatchFunc func(s string) bool
|
||||
|
||||
// Match satisfies the StringMatcher interface
|
||||
func (fn StringMatchFunc) Match(s string) bool {
|
||||
return fn(s)
|
||||
}
|
||||
|
||||
type (
|
||||
// MarshalFunc define
|
||||
MarshalFunc func(v any) ([]byte, error)
|
||||
@@ -40,3 +8,15 @@ type (
|
||||
// UnmarshalFunc define
|
||||
UnmarshalFunc func(bts []byte, ptr any) error
|
||||
)
|
||||
|
||||
// IntCheckFunc check func
|
||||
type IntCheckFunc func(val int) error
|
||||
|
||||
// StrCheckFunc check func
|
||||
type StrCheckFunc func(val string) error
|
||||
|
||||
// ToStringFunc try to convert value to string, return error on fail
|
||||
type ToStringFunc func(v any) (string, error)
|
||||
|
||||
// SafeStringFunc safe convert value to string
|
||||
type SafeStringFunc func(v any) string
|
||||
|
||||
70
vendor/github.com/gookit/goutil/comdef/interface.go
generated
vendored
Normal file
70
vendor/github.com/gookit/goutil/comdef/interface.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
package comdef
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// ByteStringWriter interface
|
||||
type ByteStringWriter interface {
|
||||
io.Writer
|
||||
io.ByteWriter
|
||||
io.StringWriter
|
||||
fmt.Stringer
|
||||
}
|
||||
|
||||
// StringWriteStringer interface
|
||||
type StringWriteStringer interface {
|
||||
io.StringWriter
|
||||
fmt.Stringer
|
||||
}
|
||||
|
||||
// Int64able interface
|
||||
type Int64able interface {
|
||||
Int64() (int64, error)
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// Matcher type
|
||||
//
|
||||
//
|
||||
|
||||
// Matcher interface
|
||||
type Matcher[T any] interface {
|
||||
Match(s T) bool
|
||||
}
|
||||
|
||||
// MatchFunc definition. implements Matcher interface
|
||||
type MatchFunc[T any] func(v T) bool
|
||||
|
||||
// Match satisfies the Matcher interface
|
||||
func (fn MatchFunc[T]) Match(v T) bool {
|
||||
return fn(v)
|
||||
}
|
||||
|
||||
// StringMatcher interface
|
||||
type StringMatcher interface {
|
||||
Match(s string) bool
|
||||
}
|
||||
|
||||
// StringMatchFunc definition
|
||||
type StringMatchFunc func(s string) bool
|
||||
|
||||
// Match satisfies the StringMatcher interface
|
||||
func (fn StringMatchFunc) Match(s string) bool {
|
||||
return fn(s)
|
||||
}
|
||||
|
||||
// StringHandler interface
|
||||
type StringHandler interface {
|
||||
Handle(s string) string
|
||||
}
|
||||
|
||||
// StringHandleFunc definition
|
||||
type StringHandleFunc func(s string) string
|
||||
|
||||
// Handle satisfies the StringHandler interface
|
||||
func (fn StringHandleFunc) Handle(s string) string {
|
||||
return fn(s)
|
||||
}
|
||||
29
vendor/github.com/gookit/goutil/comdef/types.go
generated
vendored
29
vendor/github.com/gookit/goutil/comdef/types.go
generated
vendored
@@ -10,11 +10,16 @@ type Uint interface {
|
||||
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
|
||||
}
|
||||
|
||||
// Xint interface type. all int or uint types
|
||||
// Xint interface type. alias of Integer
|
||||
type Xint interface {
|
||||
Int | Uint
|
||||
}
|
||||
|
||||
// Integer interface type. all int or uint types
|
||||
type Integer interface {
|
||||
Int | Uint
|
||||
}
|
||||
|
||||
// Float interface type
|
||||
type Float interface {
|
||||
~float32 | ~float64
|
||||
@@ -30,16 +35,34 @@ type XintOrFloat interface {
|
||||
Int | Uint | Float
|
||||
}
|
||||
|
||||
// SortedType interface type.
|
||||
// that supports the operators < <= >= >.
|
||||
// SortedType interface type. same of constraints.Ordered
|
||||
//
|
||||
// it can be ordered, that supports the operators < <= >= >.
|
||||
//
|
||||
// contains: (x)int, float, ~string types
|
||||
type SortedType interface {
|
||||
Int | Uint | Float | ~string
|
||||
}
|
||||
|
||||
// Compared type. alias of constraints.SortedType
|
||||
//
|
||||
// TODO: use type alias, will error on go1.18 Error: types.go:50: interface contains type constraints
|
||||
// type Compared = SortedType
|
||||
type Compared interface {
|
||||
Int | Uint | Float | ~string
|
||||
}
|
||||
|
||||
// SimpleType interface type. alias of ScalarType
|
||||
//
|
||||
// contains: (x)int, float, ~string, ~bool types
|
||||
type SimpleType interface {
|
||||
Int | Uint | Float | ~string | ~bool
|
||||
}
|
||||
|
||||
// ScalarType interface type.
|
||||
//
|
||||
// TIP: has bool type, it cannot be ordered
|
||||
//
|
||||
// contains: (x)int, float, ~string, ~bool types
|
||||
type ScalarType interface {
|
||||
Int | Uint | Float | ~string | ~bool
|
||||
|
||||
162
vendor/github.com/gookit/goutil/conv.go
generated
vendored
162
vendor/github.com/gookit/goutil/conv.go
generated
vendored
@@ -1,9 +1,12 @@
|
||||
package goutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
"github.com/gookit/goutil/mathutil"
|
||||
"github.com/gookit/goutil/reflects"
|
||||
@@ -65,18 +68,167 @@ func ToUint(v any) (uint64, error) {
|
||||
return mathutil.ToUint(v)
|
||||
}
|
||||
|
||||
// BoolString convert bool to string
|
||||
func BoolString(bl bool) string {
|
||||
return strconv.FormatBool(bl)
|
||||
}
|
||||
|
||||
// BaseTypeVal convert custom type or intX,uintX,floatX to generic base type.
|
||||
//
|
||||
// intX/unitX => int64
|
||||
// intX => int64
|
||||
// unitX => uint64
|
||||
// floatX => float64
|
||||
// string => string
|
||||
//
|
||||
// returns int64,string,float or error
|
||||
// returns int64,uint64,string,float or error
|
||||
func BaseTypeVal(val any) (value any, err error) {
|
||||
return reflects.BaseTypeVal(reflect.ValueOf(val))
|
||||
}
|
||||
|
||||
// BoolString convert
|
||||
func BoolString(bl bool) string {
|
||||
return strconv.FormatBool(bl)
|
||||
// SafeKind convert input any value to given reflect.Kind type.
|
||||
func SafeKind(val any, kind reflect.Kind) (newVal any) {
|
||||
newVal, _ = ToKind(val, kind, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// SafeConv convert input any value to given reflect.Kind type.
|
||||
func SafeConv(val any, kind reflect.Kind) (newVal any) {
|
||||
newVal, _ = ToKind(val, kind, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// ConvTo convert input any value to given reflect.Kind.
|
||||
func ConvTo(val any, kind reflect.Kind) (newVal any, err error) {
|
||||
return ToKind(val, kind, nil)
|
||||
}
|
||||
|
||||
// ConvOrDefault convert input any value to given reflect.Kind.
|
||||
// if fail will return default value.
|
||||
func ConvOrDefault(val any, kind reflect.Kind, defVal any) any {
|
||||
newVal, err := ToKind(val, kind, nil)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return newVal
|
||||
}
|
||||
|
||||
// ToType
|
||||
// func ToType[T any](val any, kind reflect.Kind, fbFunc func(val any) (T, error)) (newVal T, err error) {
|
||||
// switch typVal.(type) { // assert ERROR
|
||||
// case string:
|
||||
// }
|
||||
// }
|
||||
|
||||
// ToKind convert input any value to given reflect.Kind type.
|
||||
//
|
||||
// TIPs: Only support kind: string, bool, intX, uintX, floatX
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// val, err := ToKind("123", reflect.Int) // 123
|
||||
func ToKind(val any, kind reflect.Kind, fbFunc func(val any) (any, error)) (newVal any, err error) {
|
||||
switch kind {
|
||||
case reflect.Int:
|
||||
var dstV int
|
||||
if dstV, err = mathutil.ToInt(val); err == nil {
|
||||
if dstV > math.MaxInt {
|
||||
return nil, fmt.Errorf("value overflow int. val: %v", val)
|
||||
}
|
||||
newVal = dstV
|
||||
}
|
||||
case reflect.Int8:
|
||||
var dstV int
|
||||
if dstV, err = mathutil.ToInt(val); err == nil {
|
||||
if dstV > math.MaxInt8 {
|
||||
return nil, fmt.Errorf("value overflow int8. val: %v", val)
|
||||
}
|
||||
newVal = int8(dstV)
|
||||
}
|
||||
case reflect.Int16:
|
||||
var dstV int
|
||||
if dstV, err = mathutil.ToInt(val); err == nil {
|
||||
if dstV > math.MaxInt16 {
|
||||
return nil, fmt.Errorf("value overflow int16. val: %v", val)
|
||||
}
|
||||
newVal = int16(dstV)
|
||||
}
|
||||
case reflect.Int32:
|
||||
var dstV int
|
||||
if dstV, err = mathutil.ToInt(val); err == nil {
|
||||
if dstV > math.MaxInt32 {
|
||||
return nil, fmt.Errorf("value overflow int32. val: %v", val)
|
||||
}
|
||||
newVal = int32(dstV)
|
||||
}
|
||||
case reflect.Int64:
|
||||
var dstV int64
|
||||
if dstV, err = mathutil.ToInt64(val); err == nil {
|
||||
newVal = dstV
|
||||
}
|
||||
case reflect.Uint:
|
||||
var dstV uint64
|
||||
if dstV, err = mathutil.ToUint(val); err == nil {
|
||||
newVal = uint(dstV)
|
||||
}
|
||||
case reflect.Uint8:
|
||||
var dstV uint64
|
||||
if dstV, err = mathutil.ToUint(val); err == nil {
|
||||
if dstV > math.MaxUint8 {
|
||||
return nil, fmt.Errorf("value overflow uint8. val: %v", val)
|
||||
}
|
||||
newVal = uint8(dstV)
|
||||
}
|
||||
case reflect.Uint16:
|
||||
var dstV uint64
|
||||
if dstV, err = mathutil.ToUint(val); err == nil {
|
||||
if dstV > math.MaxUint16 {
|
||||
return nil, fmt.Errorf("value overflow uint16. val: %v", val)
|
||||
}
|
||||
newVal = uint16(dstV)
|
||||
}
|
||||
case reflect.Uint32:
|
||||
var dstV uint64
|
||||
if dstV, err = mathutil.ToUint(val); err == nil {
|
||||
if dstV > math.MaxUint32 {
|
||||
return nil, fmt.Errorf("value overflow uint32. val: %v", val)
|
||||
}
|
||||
newVal = uint32(dstV)
|
||||
}
|
||||
case reflect.Uint64:
|
||||
var dstV uint64
|
||||
if dstV, err = mathutil.ToUint(val); err == nil {
|
||||
newVal = dstV
|
||||
}
|
||||
case reflect.Float32:
|
||||
var dstV float64
|
||||
if dstV, err = mathutil.ToFloat(val); err == nil {
|
||||
if dstV > math.MaxFloat32 {
|
||||
return nil, fmt.Errorf("value overflow float32. val: %v", val)
|
||||
}
|
||||
newVal = float32(dstV)
|
||||
}
|
||||
case reflect.Float64:
|
||||
var dstV float64
|
||||
if dstV, err = mathutil.ToFloat(val); err == nil {
|
||||
newVal = dstV
|
||||
}
|
||||
case reflect.String:
|
||||
var dstV string
|
||||
if dstV, err = strutil.ToString(val); err == nil {
|
||||
newVal = dstV
|
||||
}
|
||||
case reflect.Bool:
|
||||
if bl, err1 := comfunc.ToBool(val); err1 == nil {
|
||||
newVal = bl
|
||||
} else {
|
||||
err = err1
|
||||
}
|
||||
default:
|
||||
if fbFunc != nil {
|
||||
newVal, err = fbFunc(val)
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
66
vendor/github.com/gookit/goutil/encodes/encodes.go
generated
vendored
Normal file
66
vendor/github.com/gookit/goutil/encodes/encodes.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package encodes
|
||||
|
||||
import (
|
||||
"encoding/base32"
|
||||
"encoding/base64"
|
||||
)
|
||||
|
||||
// BaseEncoder interface
|
||||
type BaseEncoder interface {
|
||||
Encode(dst []byte, src []byte)
|
||||
EncodeToString(src []byte) string
|
||||
Decode(dst []byte, src []byte) (n int, err error)
|
||||
DecodeString(s string) ([]byte, error)
|
||||
}
|
||||
|
||||
//
|
||||
// -------------------- base encode --------------------
|
||||
//
|
||||
|
||||
// base32 encoding with no padding
|
||||
var (
|
||||
B32Std = base32.StdEncoding.WithPadding(base32.NoPadding)
|
||||
B32Hex = base32.HexEncoding.WithPadding(base32.NoPadding)
|
||||
)
|
||||
|
||||
// B32Encode base32 encode
|
||||
func B32Encode(str string) string {
|
||||
return B32Std.EncodeToString([]byte(str))
|
||||
}
|
||||
|
||||
// B32Decode base32 decode
|
||||
func B32Decode(str string) string {
|
||||
dec, _ := B32Std.DecodeString(str)
|
||||
return string(dec)
|
||||
}
|
||||
|
||||
// base64 encoding with no padding
|
||||
var (
|
||||
B64Std = base64.StdEncoding.WithPadding(base64.NoPadding)
|
||||
B64URL = base64.URLEncoding.WithPadding(base64.NoPadding)
|
||||
)
|
||||
|
||||
// B64Encode base64 encode
|
||||
func B64Encode(str string) string {
|
||||
return B64Std.EncodeToString([]byte(str))
|
||||
}
|
||||
|
||||
// B64EncodeBytes base64 encode
|
||||
func B64EncodeBytes(src []byte) []byte {
|
||||
buf := make([]byte, B64Std.EncodedLen(len(src)))
|
||||
B64Std.Encode(buf, src)
|
||||
return buf
|
||||
}
|
||||
|
||||
// B64Decode base64 decode
|
||||
func B64Decode(str string) string {
|
||||
dec, _ := B64Std.DecodeString(str)
|
||||
return string(dec)
|
||||
}
|
||||
|
||||
// B64DecodeBytes base64 decode
|
||||
func B64DecodeBytes(str []byte) []byte {
|
||||
dbuf := make([]byte, B64Std.DecodedLen(len(str)))
|
||||
n, _ := B64Std.Decode(dbuf, str)
|
||||
return dbuf[:n]
|
||||
}
|
||||
2
vendor/github.com/gookit/goutil/envutil/README.md
generated
vendored
2
vendor/github.com/gookit/goutil/envutil/README.md
generated
vendored
@@ -1,6 +1,6 @@
|
||||
# Env Util
|
||||
|
||||
Provide some commonly ENV util functions.
|
||||
Provide some commonly system or go ENV util functions.
|
||||
|
||||
## Install
|
||||
|
||||
|
||||
31
vendor/github.com/gookit/goutil/envutil/envutil.go
generated
vendored
31
vendor/github.com/gookit/goutil/envutil/envutil.go
generated
vendored
@@ -4,7 +4,7 @@ package envutil
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
"github.com/gookit/goutil/internal/varexpr"
|
||||
)
|
||||
|
||||
// ValueGetter Env value provider func.
|
||||
@@ -17,14 +17,13 @@ var ValueGetter = os.Getenv
|
||||
// is alias of the os.ExpandEnv()
|
||||
func VarReplace(s string) string { return os.ExpandEnv(s) }
|
||||
|
||||
// VarParse alias of the ParseValue
|
||||
func VarParse(val string) string {
|
||||
return comfunc.ParseEnvVar(val, ValueGetter)
|
||||
}
|
||||
|
||||
// ParseEnvValue alias of the ParseValue
|
||||
func ParseEnvValue(val string) string {
|
||||
return comfunc.ParseEnvVar(val, ValueGetter)
|
||||
// ParseOrErr parse ENV var value from input string, support default value.
|
||||
//
|
||||
// Diff with the ParseValue, this support return error.
|
||||
//
|
||||
// With error format: ${VAR_NAME | ?error}
|
||||
func ParseOrErr(val string) (string, error) {
|
||||
return varexpr.Parse(val)
|
||||
}
|
||||
|
||||
// ParseValue parse ENV var value from input string, support default value.
|
||||
@@ -38,8 +37,18 @@ func ParseEnvValue(val string) string {
|
||||
//
|
||||
// envutil.ParseValue("${ APP_NAME }")
|
||||
// envutil.ParseValue("${ APP_ENV | dev }")
|
||||
func ParseValue(val string) (newVal string) {
|
||||
return comfunc.ParseEnvVar(val, ValueGetter)
|
||||
func ParseValue(val string) string {
|
||||
return varexpr.SafeParse(val)
|
||||
}
|
||||
|
||||
// VarParse alias of the ParseValue
|
||||
func VarParse(val string) string {
|
||||
return varexpr.SafeParse(val)
|
||||
}
|
||||
|
||||
// ParseEnvValue alias of the ParseValue
|
||||
func ParseEnvValue(val string) string {
|
||||
return varexpr.SafeParse(val)
|
||||
}
|
||||
|
||||
// SetEnvMap set multi ENV(string-map) to os
|
||||
|
||||
13
vendor/github.com/gookit/goutil/envutil/get.go
generated
vendored
13
vendor/github.com/gookit/goutil/envutil/get.go
generated
vendored
@@ -4,6 +4,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gookit/goutil/basefn"
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
"github.com/gookit/goutil/strutil"
|
||||
)
|
||||
@@ -22,11 +23,7 @@ func GetInt(name string, def ...int) int {
|
||||
if val := os.Getenv(name); val != "" {
|
||||
return strutil.QuietInt(val)
|
||||
}
|
||||
|
||||
if len(def) > 0 {
|
||||
return def[0]
|
||||
}
|
||||
return 0
|
||||
return basefn.FirstOr(def, 0)
|
||||
}
|
||||
|
||||
// GetBool get bool ENV value by key name, can with default value
|
||||
@@ -34,11 +31,7 @@ func GetBool(name string, def ...bool) bool {
|
||||
if val := os.Getenv(name); val != "" {
|
||||
return strutil.QuietBool(val)
|
||||
}
|
||||
|
||||
if len(def) > 0 {
|
||||
return def[0]
|
||||
}
|
||||
return false
|
||||
return basefn.FirstOr(def, false)
|
||||
}
|
||||
|
||||
// GetMulti ENV values by input names.
|
||||
|
||||
10
vendor/github.com/gookit/goutil/errorx/assert.go
generated
vendored
10
vendor/github.com/gookit/goutil/errorx/assert.go
generated
vendored
@@ -30,7 +30,7 @@ func IsIn[T comdef.ScalarType](value T, list []T, fmtAndArgs ...any) error {
|
||||
if arrutil.NotIn(value, list) {
|
||||
var errMsg string
|
||||
if len(fmtAndArgs) > 0 {
|
||||
errMsg = comfunc.FormatTplAndArgs(fmtAndArgs)
|
||||
errMsg = comfunc.FormatWithArgs(fmtAndArgs)
|
||||
} else {
|
||||
errMsg = fmt.Sprintf("value should be in the %v", list)
|
||||
}
|
||||
@@ -44,7 +44,7 @@ func NotIn[T comdef.ScalarType](value T, list []T, fmtAndArgs ...any) error {
|
||||
if arrutil.In(value, list) {
|
||||
var errMsg string
|
||||
if len(fmtAndArgs) > 0 {
|
||||
errMsg = comfunc.FormatTplAndArgs(fmtAndArgs)
|
||||
errMsg = comfunc.FormatWithArgs(fmtAndArgs)
|
||||
} else {
|
||||
errMsg = fmt.Sprintf("value should not be in the %v", list)
|
||||
}
|
||||
@@ -53,9 +53,9 @@ func NotIn[T comdef.ScalarType](value T, list []T, fmtAndArgs ...any) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func formatErrMsg(errMsg string, fmtAndArgs []any) string {
|
||||
func formatErrMsg(defMsg string, fmtAndArgs []any) string {
|
||||
if len(fmtAndArgs) > 0 {
|
||||
errMsg = comfunc.FormatTplAndArgs(fmtAndArgs)
|
||||
return comfunc.FormatWithArgs(fmtAndArgs)
|
||||
}
|
||||
return errMsg
|
||||
return defMsg
|
||||
}
|
||||
|
||||
15
vendor/github.com/gookit/goutil/errorx/errors.go
generated
vendored
15
vendor/github.com/gookit/goutil/errorx/errors.go
generated
vendored
@@ -77,11 +77,14 @@ func (e *errorR) GoString() string {
|
||||
return e.String()
|
||||
}
|
||||
|
||||
// ErrMap multi error map
|
||||
type ErrMap map[string]error
|
||||
// ErrorM multi error map
|
||||
type ErrorM map[string]error
|
||||
|
||||
// ErrMap alias of ErrorM
|
||||
type ErrMap = ErrorM
|
||||
|
||||
// Error string
|
||||
func (e ErrMap) Error() string {
|
||||
func (e ErrorM) Error() string {
|
||||
var sb strings.Builder
|
||||
for name, err := range e {
|
||||
sb.WriteString(name)
|
||||
@@ -93,7 +96,7 @@ func (e ErrMap) Error() string {
|
||||
}
|
||||
|
||||
// ErrorOrNil error
|
||||
func (e ErrMap) ErrorOrNil() error {
|
||||
func (e ErrorM) ErrorOrNil() error {
|
||||
if len(e) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -101,12 +104,12 @@ func (e ErrMap) ErrorOrNil() error {
|
||||
}
|
||||
|
||||
// IsEmpty error
|
||||
func (e ErrMap) IsEmpty() bool {
|
||||
func (e ErrorM) IsEmpty() bool {
|
||||
return len(e) == 0
|
||||
}
|
||||
|
||||
// One error
|
||||
func (e ErrMap) One() error {
|
||||
func (e ErrorM) One() error {
|
||||
for _, err := range e {
|
||||
return err
|
||||
}
|
||||
|
||||
7
vendor/github.com/gookit/goutil/errorx/errorx.go
generated
vendored
7
vendor/github.com/gookit/goutil/errorx/errorx.go
generated
vendored
@@ -71,7 +71,7 @@ func (e *ErrorX) Unwrap() error {
|
||||
return e.prev
|
||||
}
|
||||
|
||||
// Format error
|
||||
// Format error, will output stack information.
|
||||
func (e *ErrorX) Format(s fmt.State, verb rune) {
|
||||
// format current error: only output on have msg
|
||||
if len(e.msg) > 0 {
|
||||
@@ -103,7 +103,7 @@ func (e *ErrorX) GoString() string {
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// Error to string, not contains stack information.
|
||||
// Error msg string, not contains stack information.
|
||||
func (e *ErrorX) Error() string {
|
||||
var buf bytes.Buffer
|
||||
e.writeMsgTo(&buf)
|
||||
@@ -265,6 +265,7 @@ func WithStack(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ErrorX{
|
||||
msg: err.Error(),
|
||||
// prev: err,
|
||||
@@ -277,6 +278,7 @@ func Traced(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ErrorX{
|
||||
msg: err.Error(),
|
||||
stack: callersStack(stdOpt.SkipDepth, stdOpt.TraceDepth),
|
||||
@@ -288,6 +290,7 @@ func Stacked(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &ErrorX{
|
||||
msg: err.Error(),
|
||||
stack: callersStack(stdOpt.SkipDepth, stdOpt.TraceDepth),
|
||||
|
||||
4
vendor/github.com/gookit/goutil/errorx/stack.go
generated
vendored
4
vendor/github.com/gookit/goutil/errorx/stack.go
generated
vendored
@@ -99,7 +99,7 @@ func FuncForPC(pc uintptr) *Func {
|
||||
}
|
||||
}
|
||||
|
||||
// FileLine of the func
|
||||
// FileLine returns the file name and line number of the source code
|
||||
func (f *Func) FileLine() (file string, line int) {
|
||||
return f.Func.FileLine(f.pc)
|
||||
}
|
||||
@@ -108,7 +108,7 @@ func (f *Func) FileLine() (file string, line int) {
|
||||
//
|
||||
// Returns eg:
|
||||
//
|
||||
// github.com/gookit/goutil/errorx_test.TestWithPrev(), errorx_test.go:34
|
||||
// "github.com/gookit/goutil/errorx_test.TestWithPrev(), errorx_test.go:34"
|
||||
func (f *Func) Location() string {
|
||||
file, line := f.FileLine()
|
||||
|
||||
|
||||
15
vendor/github.com/gookit/goutil/errorx/util.go
generated
vendored
15
vendor/github.com/gookit/goutil/errorx/util.go
generated
vendored
@@ -68,12 +68,27 @@ func Unwrap(err error) error {
|
||||
// Previous alias of Unwrap()
|
||||
func Previous(err error) error { return Unwrap(err) }
|
||||
|
||||
// IsErrorX check
|
||||
func IsErrorX(err error) (ok bool) {
|
||||
_, ok = err.(*ErrorX)
|
||||
return
|
||||
}
|
||||
|
||||
// ToErrorX convert check
|
||||
func ToErrorX(err error) (ex *ErrorX, ok bool) {
|
||||
ex, ok = err.(*ErrorX)
|
||||
return
|
||||
}
|
||||
|
||||
// MustEX convert error to *ErrorX, panic if err check failed.
|
||||
func MustEX(err error) *ErrorX {
|
||||
ex, ok := err.(*ErrorX)
|
||||
if !ok {
|
||||
panic("errorx: error is not *ErrorX")
|
||||
}
|
||||
return ex
|
||||
}
|
||||
|
||||
// Has contains target error, or err is eq target.
|
||||
// alias of errors.Is()
|
||||
func Has(err, target error) bool {
|
||||
|
||||
13
vendor/github.com/gookit/goutil/fsutil/check.go
generated
vendored
13
vendor/github.com/gookit/goutil/fsutil/check.go
generated
vendored
@@ -2,6 +2,7 @@ package fsutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
@@ -82,6 +83,18 @@ func IsAbsPath(aPath string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsEmptyDir reports whether the named directory is empty.
|
||||
func IsEmptyDir(dirPath string) bool {
|
||||
f, err := os.Open(dirPath)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.Readdirnames(1)
|
||||
return err == io.EOF
|
||||
}
|
||||
|
||||
// ImageMimeTypes refer net/http package
|
||||
var ImageMimeTypes = map[string]string{
|
||||
"bmp": "image/bmp",
|
||||
|
||||
109
vendor/github.com/gookit/goutil/fsutil/define.go
generated
vendored
Normal file
109
vendor/github.com/gookit/goutil/fsutil/define.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
package fsutil
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
"github.com/gookit/goutil/strutil"
|
||||
)
|
||||
|
||||
const (
|
||||
// MimeSniffLen sniff Length, use for detect file mime type
|
||||
MimeSniffLen = 512
|
||||
)
|
||||
|
||||
// NameMatchFunc name match func, alias of comdef.StringMatchFunc
|
||||
type NameMatchFunc = comdef.StringMatchFunc
|
||||
|
||||
// PathMatchFunc path match func. alias of comdef.StringMatchFunc
|
||||
type PathMatchFunc = comdef.StringMatchFunc
|
||||
|
||||
// Entry extends fs.DirEntry, add some useful methods
|
||||
type Entry interface {
|
||||
fs.DirEntry
|
||||
// Path get file/dir full path. eg: "/path/to/file.go"
|
||||
Path() string
|
||||
// Info get file info. like fs.DirEntry.Info(), but will cache result.
|
||||
Info() (fs.FileInfo, error)
|
||||
}
|
||||
|
||||
type entry struct {
|
||||
fs.DirEntry
|
||||
path string
|
||||
stat fs.FileInfo
|
||||
sErr error
|
||||
}
|
||||
|
||||
// NewEntry create a new Entry instance
|
||||
func NewEntry(fPath string, ent fs.DirEntry) Entry {
|
||||
return &entry{
|
||||
path: fPath,
|
||||
DirEntry: ent,
|
||||
}
|
||||
}
|
||||
|
||||
// Path get full file/dir path. eg: "/path/to/file.go"
|
||||
func (e *entry) Path() string {
|
||||
return e.path
|
||||
}
|
||||
|
||||
// Info get file info, will cache result
|
||||
func (e *entry) Info() (fs.FileInfo, error) {
|
||||
if e.stat == nil {
|
||||
e.stat, e.sErr = e.DirEntry.Info()
|
||||
}
|
||||
return e.stat, e.sErr
|
||||
}
|
||||
|
||||
// String get string representation
|
||||
func (e *entry) String() string {
|
||||
return strutil.OrCond(e.IsDir(), "dir: ", "file: ") + e.Path()
|
||||
}
|
||||
|
||||
// FileInfo extends fs.FileInfo, add some useful methods
|
||||
type FileInfo interface {
|
||||
fs.FileInfo
|
||||
// Path get file full path. eg: "/path/to/file.go"
|
||||
Path() string
|
||||
}
|
||||
|
||||
type fileInfo struct {
|
||||
fs.FileInfo
|
||||
fullPath string
|
||||
}
|
||||
|
||||
// NewFileInfo create a new FileInfo instance
|
||||
func NewFileInfo(fPath string, info fs.FileInfo) FileInfo {
|
||||
return &fileInfo{
|
||||
fullPath: fPath,
|
||||
FileInfo: info,
|
||||
}
|
||||
}
|
||||
|
||||
// Path get file full path. eg: "/path/to/file.go"
|
||||
func (fi *fileInfo) Path() string {
|
||||
return fi.fullPath
|
||||
}
|
||||
|
||||
// FileInfos type for FileInfo slice
|
||||
//
|
||||
// implements sort.Interface:
|
||||
//
|
||||
// sorts by oldest time modified in the file info.
|
||||
// eg: [old_220211, old_220212, old_220213]
|
||||
type FileInfos []FileInfo
|
||||
|
||||
// Len get length
|
||||
func (fis FileInfos) Len() int {
|
||||
return len(fis)
|
||||
}
|
||||
|
||||
// Swap swap values
|
||||
func (fis FileInfos) Swap(i, j int) {
|
||||
fis[i], fis[j] = fis[j], fis[i]
|
||||
}
|
||||
|
||||
// Less check by mod time
|
||||
func (fis FileInfos) Less(i, j int) bool {
|
||||
return fis[j].ModTime().After(fis[i].ModTime())
|
||||
}
|
||||
60
vendor/github.com/gookit/goutil/fsutil/find.go
generated
vendored
60
vendor/github.com/gookit/goutil/fsutil/find.go
generated
vendored
@@ -7,10 +7,66 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gookit/goutil/arrutil"
|
||||
"github.com/gookit/goutil/comdef"
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
"github.com/gookit/goutil/strutil"
|
||||
)
|
||||
|
||||
// FilePathInDirs get full file path in dirs.
|
||||
//
|
||||
// Params:
|
||||
// - file: can be relative path, file name, full path.
|
||||
// - dirs: dir paths
|
||||
func FilePathInDirs(file string, dirs ...string) string {
|
||||
file = comfunc.ExpandHome(file)
|
||||
if FileExists(file) {
|
||||
return file
|
||||
}
|
||||
|
||||
for _, dirPath := range dirs {
|
||||
fPath := JoinSubPaths(dirPath, file)
|
||||
if FileExists(fPath) {
|
||||
return fPath
|
||||
}
|
||||
}
|
||||
return "" // not found
|
||||
}
|
||||
|
||||
// FirstExists check multi paths and return first exists path.
|
||||
func FirstExists(paths ...string) string {
|
||||
return MatchFirst(paths, PathExists, "")
|
||||
}
|
||||
|
||||
// FirstExistsDir check multi paths and return first exists dir.
|
||||
func FirstExistsDir(paths ...string) string {
|
||||
return MatchFirst(paths, IsDir, "")
|
||||
}
|
||||
|
||||
// FirstExistsFile check multi paths and return first exists file.
|
||||
func FirstExistsFile(paths ...string) string {
|
||||
return MatchFirst(paths, IsFile, "")
|
||||
}
|
||||
|
||||
// MatchPaths given paths by custom mather func.
|
||||
func MatchPaths(paths []string, matcher PathMatchFunc) []string {
|
||||
var ret []string
|
||||
for _, p := range paths {
|
||||
if matcher(p) {
|
||||
ret = append(ret, p)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// MatchFirst filter paths by filter func and return first match path.
|
||||
func MatchFirst(paths []string, matcher PathMatchFunc, defaultPath string) string {
|
||||
for _, p := range paths {
|
||||
if matcher(p) {
|
||||
return p
|
||||
}
|
||||
}
|
||||
return defaultPath
|
||||
}
|
||||
|
||||
// SearchNameUp find file/dir name in dirPath or parent dirs,
|
||||
// return the name of directory path
|
||||
//
|
||||
@@ -57,7 +113,7 @@ func WalkDir(dir string, fn fs.WalkDirFunc) error {
|
||||
// Usage:
|
||||
//
|
||||
// files := fsutil.Glob("/path/to/dir/*.go")
|
||||
func Glob(pattern string, fls ...comdef.StringMatchFunc) []string {
|
||||
func Glob(pattern string, fls ...NameMatchFunc) []string {
|
||||
files, _ := filepath.Glob(pattern)
|
||||
if len(fls) == 0 || len(files) == 0 {
|
||||
return files
|
||||
|
||||
73
vendor/github.com/gookit/goutil/fsutil/fsutil.go
generated
vendored
73
vendor/github.com/gookit/goutil/fsutil/fsutil.go
generated
vendored
@@ -2,8 +2,6 @@
|
||||
package fsutil
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -11,77 +9,6 @@ import (
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
)
|
||||
|
||||
const (
|
||||
// MimeSniffLen sniff Length, use for detect file mime type
|
||||
MimeSniffLen = 512
|
||||
)
|
||||
|
||||
// OSTempFile create a temp file on os.TempDir()
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// fsutil.OSTempFile("example.*.txt")
|
||||
func OSTempFile(pattern string) (*os.File, error) {
|
||||
return os.CreateTemp(os.TempDir(), pattern)
|
||||
}
|
||||
|
||||
// TempFile is like os.CreateTemp, but can custom temp dir.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// fsutil.TempFile("", "example.*.txt")
|
||||
func TempFile(dir, pattern string) (*os.File, error) {
|
||||
return os.CreateTemp(dir, pattern)
|
||||
}
|
||||
|
||||
// OSTempDir creates a new temp dir on os.TempDir and return the temp dir path
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// fsutil.OSTempDir("example.*")
|
||||
func OSTempDir(pattern string) (string, error) {
|
||||
return os.MkdirTemp(os.TempDir(), pattern)
|
||||
}
|
||||
|
||||
// TempDir creates a new temp dir and return the temp dir path
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// fsutil.TempDir("", "example.*")
|
||||
// fsutil.TempDir("testdata", "example.*")
|
||||
func TempDir(dir, pattern string) (string, error) {
|
||||
return os.MkdirTemp(dir, pattern)
|
||||
}
|
||||
|
||||
// MimeType get File Mime Type name. eg "image/png"
|
||||
func MimeType(path string) (mime string) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return ReaderMimeType(file)
|
||||
}
|
||||
|
||||
// ReaderMimeType get the io.Reader mimeType
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// file, err := os.Open(filepath)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// mime := ReaderMimeType(file)
|
||||
func ReaderMimeType(r io.Reader) (mime string) {
|
||||
var buf [MimeSniffLen]byte
|
||||
n, _ := io.ReadFull(r, buf[:])
|
||||
if n == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return http.DetectContentType(buf[:n])
|
||||
}
|
||||
|
||||
// JoinPaths elements, alias of filepath.Join()
|
||||
func JoinPaths(elem ...string) string {
|
||||
return filepath.Join(elem...)
|
||||
|
||||
3
vendor/github.com/gookit/goutil/fsutil/info.go
generated
vendored
3
vendor/github.com/gookit/goutil/fsutil/info.go
generated
vendored
@@ -8,6 +8,9 @@ import (
|
||||
"github.com/gookit/goutil/internal/comfunc"
|
||||
)
|
||||
|
||||
// DirPath get dir path from filepath, without last name.
|
||||
func DirPath(fpath string) string { return filepath.Dir(fpath) }
|
||||
|
||||
// Dir get dir path from filepath, without last name.
|
||||
func Dir(fpath string) string { return filepath.Dir(fpath) }
|
||||
|
||||
|
||||
1
vendor/github.com/gookit/goutil/fsutil/info_nonwin.go
generated
vendored
1
vendor/github.com/gookit/goutil/fsutil/info_nonwin.go
generated
vendored
@@ -9,6 +9,7 @@ import (
|
||||
)
|
||||
|
||||
// Realpath returns the shortest path name equivalent to path by purely lexical processing.
|
||||
// Will expand ~ to home dir, and join with workdir if path is relative path.
|
||||
func Realpath(pathStr string) string {
|
||||
pathStr = comfunc.ExpandHome(pathStr)
|
||||
|
||||
|
||||
40
vendor/github.com/gookit/goutil/fsutil/mime.go
generated
vendored
Normal file
40
vendor/github.com/gookit/goutil/fsutil/mime.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
package fsutil
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
// DetectMime detect file mime type. alias of MimeType()
|
||||
func DetectMime(path string) string {
|
||||
return MimeType(path)
|
||||
}
|
||||
|
||||
// MimeType get file mime type name. eg "image/png"
|
||||
func MimeType(path string) (mime string) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return ReaderMimeType(file)
|
||||
}
|
||||
|
||||
// ReaderMimeType get the io.Reader mimeType
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// file, err := os.Open(filepath)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// mime := ReaderMimeType(file)
|
||||
func ReaderMimeType(r io.Reader) (mime string) {
|
||||
var buf [MimeSniffLen]byte
|
||||
n, _ := io.ReadFull(r, buf[:])
|
||||
if n == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return http.DetectContentType(buf[:n])
|
||||
}
|
||||
79
vendor/github.com/gookit/goutil/fsutil/operate.go
generated
vendored
79
vendor/github.com/gookit/goutil/fsutil/operate.go
generated
vendored
@@ -39,7 +39,7 @@ func MkSubDirs(perm os.FileMode, parentDir string, subDirs ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MkParentDir quick create parent dir
|
||||
// MkParentDir quick create parent dir for given path.
|
||||
func MkParentDir(fpath string) error {
|
||||
dirPath := filepath.Dir(fpath)
|
||||
if !IsDir(dirPath) {
|
||||
@@ -48,15 +48,70 @@ func MkParentDir(fpath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ************************************************************
|
||||
// options for open file
|
||||
// ************************************************************
|
||||
|
||||
// OpenOption for open file
|
||||
type OpenOption struct {
|
||||
// file open flag. see FsCWTFlags
|
||||
Flag int
|
||||
// file perm. see DefaultFilePerm
|
||||
Perm os.FileMode
|
||||
}
|
||||
|
||||
// OpenOptionFunc for open/write file
|
||||
type OpenOptionFunc func(*OpenOption)
|
||||
|
||||
// NewOpenOption create a new OpenOption instance
|
||||
//
|
||||
// Defaults:
|
||||
// - open flags: FsCWTFlags (override write)
|
||||
// - file Perm: DefaultFilePerm
|
||||
func NewOpenOption(optFns ...OpenOptionFunc) *OpenOption {
|
||||
opt := &OpenOption{
|
||||
Flag: FsCWTFlags,
|
||||
Perm: DefaultFilePerm,
|
||||
}
|
||||
|
||||
for _, fn := range optFns {
|
||||
fn(opt)
|
||||
}
|
||||
return opt
|
||||
}
|
||||
|
||||
// OpenOptOrNew create a new OpenOption instance if opt is nil
|
||||
func OpenOptOrNew(opt *OpenOption) *OpenOption {
|
||||
if opt == nil {
|
||||
return NewOpenOption()
|
||||
}
|
||||
return opt
|
||||
}
|
||||
|
||||
// WithFlag set file open flag
|
||||
func WithFlag(flag int) OpenOptionFunc {
|
||||
return func(opt *OpenOption) {
|
||||
opt.Flag = flag
|
||||
}
|
||||
}
|
||||
|
||||
// WithPerm set file perm
|
||||
func WithPerm(perm os.FileMode) OpenOptionFunc {
|
||||
return func(opt *OpenOption) {
|
||||
opt.Perm = perm
|
||||
}
|
||||
}
|
||||
|
||||
// ************************************************************
|
||||
// open/create files
|
||||
// ************************************************************
|
||||
|
||||
// some commonly flag consts for open file
|
||||
// some commonly flag consts for open file.
|
||||
const (
|
||||
FsCWAFlags = os.O_CREATE | os.O_WRONLY | os.O_APPEND // create, append write-only
|
||||
FsCWTFlags = os.O_CREATE | os.O_WRONLY | os.O_TRUNC // create, override write-only
|
||||
FsCWFlags = os.O_CREATE | os.O_WRONLY // create, write-only
|
||||
FsRWFlags = os.O_RDWR // read-write, dont create.
|
||||
FsRFlags = os.O_RDONLY // read-only
|
||||
)
|
||||
|
||||
@@ -65,13 +120,13 @@ const (
|
||||
// Usage:
|
||||
//
|
||||
// file, err := OpenFile("path/to/file.txt", FsCWFlags, 0666)
|
||||
func OpenFile(filepath string, flag int, perm os.FileMode) (*os.File, error) {
|
||||
fileDir := path.Dir(filepath)
|
||||
func OpenFile(filePath string, flag int, perm os.FileMode) (*os.File, error) {
|
||||
fileDir := path.Dir(filePath)
|
||||
if err := os.MkdirAll(fileDir, DefaultDirPerm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(filepath, flag, perm)
|
||||
file, err := os.OpenFile(filePath, flag, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -83,8 +138,8 @@ func OpenFile(filepath string, flag int, perm os.FileMode) (*os.File, error) {
|
||||
// Usage:
|
||||
//
|
||||
// file := MustOpenFile("path/to/file.txt", FsCWFlags, 0666)
|
||||
func MustOpenFile(filepath string, flag int, perm os.FileMode) *os.File {
|
||||
file, err := OpenFile(filepath, flag, perm)
|
||||
func MustOpenFile(filePath string, flag int, perm os.FileMode) *os.File {
|
||||
file, err := OpenFile(filePath, flag, perm)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -173,6 +228,11 @@ func MustRemove(fPath string) {
|
||||
// NOTICE: will ignore error
|
||||
func QuietRemove(fPath string) { _ = os.Remove(fPath) }
|
||||
|
||||
// SafeRemoveAll removes path and any children it contains. will ignore error
|
||||
func SafeRemoveAll(path string) {
|
||||
_ = os.RemoveAll(path)
|
||||
}
|
||||
|
||||
// RmIfExist removes the named file or (empty) directory on exists.
|
||||
func RmIfExist(fPath string) error { return DeleteIfExist(fPath) }
|
||||
|
||||
@@ -202,6 +262,11 @@ func RemoveSub(dirPath string, fns ...FilterFunc) error {
|
||||
if err := RemoveSub(fPath, fns...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// skip rm not empty subdir
|
||||
if !IsEmptyDir(fPath) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return os.Remove(fPath)
|
||||
}, fns...)
|
||||
|
||||
29
vendor/github.com/gookit/goutil/fsutil/opread.go
generated
vendored
29
vendor/github.com/gookit/goutil/fsutil/opread.go
generated
vendored
@@ -6,6 +6,8 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"text/scanner"
|
||||
|
||||
"github.com/gookit/goutil/basefn"
|
||||
)
|
||||
|
||||
// NewIOReader instance by input file path or io.Reader
|
||||
@@ -70,20 +72,27 @@ func ReadStringOrErr(in any) (string, error) {
|
||||
}
|
||||
|
||||
// ReadAll read contents from path or io.Reader, will panic on in type error
|
||||
func ReadAll(in any) []byte { return GetContents(in) }
|
||||
func ReadAll(in any) []byte { return MustRead(in) }
|
||||
|
||||
// GetContents read contents from path or io.Reader, will panic on in type error
|
||||
func GetContents(in any) []byte {
|
||||
r, err := NewIOReader(in)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return MustReadReader(r)
|
||||
func GetContents(in any) []byte { return MustRead(in) }
|
||||
|
||||
// MustRead read contents from path or io.Reader, will panic on in type error
|
||||
func MustRead(in any) []byte {
|
||||
return basefn.Must(ReadOrErr(in))
|
||||
}
|
||||
|
||||
// ReadOrErr read contents from path or io.Reader, will panic on in type error
|
||||
func ReadOrErr(in any) ([]byte, error) {
|
||||
r, err := NewIOReader(in)
|
||||
defer func() {
|
||||
if r != nil {
|
||||
if file, ok := r.(*os.File); ok {
|
||||
err = file.Close()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -102,7 +111,8 @@ func ReadExistFile(filePath string) []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TextScanner from filepath or io.Reader, will panic on in type error
|
||||
// TextScanner from filepath or io.Reader, will panic on in type error.
|
||||
// Will scan parse text to tokens: Ident, Int, Float, Char, String, RawString, Comment, etc.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
@@ -122,7 +132,8 @@ func TextScanner(in any) *scanner.Scanner {
|
||||
return &s
|
||||
}
|
||||
|
||||
// LineScanner create from filepath or io.Reader
|
||||
// LineScanner create from filepath or io.Reader, will panic on in type error.
|
||||
// Will scan and parse text to lines.
|
||||
//
|
||||
// s := fsutil.LineScanner("/path/to/file")
|
||||
// for s.Scan() {
|
||||
|
||||
81
vendor/github.com/gookit/goutil/fsutil/opwrite.go
generated
vendored
81
vendor/github.com/gookit/goutil/fsutil/opwrite.go
generated
vendored
@@ -7,13 +7,73 @@ import (
|
||||
"github.com/gookit/goutil/basefn"
|
||||
)
|
||||
|
||||
// ************************************************************
|
||||
// temp file or dir
|
||||
// ************************************************************
|
||||
|
||||
// OSTempFile create a temp file on os.TempDir()
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// fsutil.OSTempFile("example.*.txt")
|
||||
func OSTempFile(pattern string) (*os.File, error) {
|
||||
return os.CreateTemp(os.TempDir(), pattern)
|
||||
}
|
||||
|
||||
// TempFile is like os.CreateTemp, but can custom temp dir.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// // create temp file on os.TempDir()
|
||||
// fsutil.TempFile("", "example.*.txt")
|
||||
// // create temp file on "testdata" dir
|
||||
// fsutil.TempFile("testdata", "example.*.txt")
|
||||
func TempFile(dir, pattern string) (*os.File, error) {
|
||||
return os.CreateTemp(dir, pattern)
|
||||
}
|
||||
|
||||
// OSTempDir creates a new temp dir on os.TempDir and return the temp dir path
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// fsutil.OSTempDir("example.*")
|
||||
func OSTempDir(pattern string) (string, error) {
|
||||
return os.MkdirTemp(os.TempDir(), pattern)
|
||||
}
|
||||
|
||||
// TempDir creates a new temp dir and return the temp dir path
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// fsutil.TempDir("", "example.*")
|
||||
// fsutil.TempDir("testdata", "example.*")
|
||||
func TempDir(dir, pattern string) (string, error) {
|
||||
return os.MkdirTemp(dir, pattern)
|
||||
}
|
||||
|
||||
// ************************************************************
|
||||
// write, copy files
|
||||
// ************************************************************
|
||||
|
||||
// PutContents create file and write contents to file at once.
|
||||
// MustSave create file and write contents to file, panic on error.
|
||||
//
|
||||
// data type allow: string, []byte, io.Reader
|
||||
// default option see NewOpenOption()
|
||||
func MustSave(filePath string, data any, optFns ...OpenOptionFunc) {
|
||||
basefn.MustOK(SaveFile(filePath, data, optFns...))
|
||||
}
|
||||
|
||||
// SaveFile create file and write contents to file. will auto create dir.
|
||||
//
|
||||
// default option see NewOpenOption()
|
||||
func SaveFile(filePath string, data any, optFns ...OpenOptionFunc) error {
|
||||
opt := NewOpenOption(optFns...)
|
||||
return WriteFile(filePath, data, opt.Perm, opt.Flag)
|
||||
}
|
||||
|
||||
// PutContents create file and write contents to file at once.
|
||||
//
|
||||
// data type allow: string, []byte, io.Reader. will auto create dir.
|
||||
//
|
||||
// Tip: file flag default is FsCWTFlags (override write)
|
||||
//
|
||||
@@ -25,7 +85,6 @@ func PutContents(filePath string, data any, fileFlag ...int) (int, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return WriteOSFile(f, data)
|
||||
}
|
||||
|
||||
@@ -99,3 +158,21 @@ func MustCopyFile(srcPath, dstPath string) {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateContents read file contents, call handleFn(contents) handle, then write updated contents to file
|
||||
func UpdateContents(filePath string, handleFn func(bs []byte) []byte) error {
|
||||
osFile, err := os.OpenFile(filePath, os.O_RDWR|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer osFile.Close()
|
||||
|
||||
// read file contents
|
||||
if bs, err1 := io.ReadAll(osFile); err1 == nil {
|
||||
bs = handleFn(bs)
|
||||
_, err = osFile.Write(bs)
|
||||
} else {
|
||||
err = err1
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
57
vendor/github.com/gookit/goutil/func.go
generated
vendored
57
vendor/github.com/gookit/goutil/func.go
generated
vendored
@@ -1,11 +1,6 @@
|
||||
package goutil
|
||||
|
||||
import "github.com/gookit/goutil/stdutil"
|
||||
|
||||
// FuncName get func name
|
||||
func FuncName(f any) string {
|
||||
return stdutil.FuncName(f)
|
||||
}
|
||||
import "fmt"
|
||||
|
||||
// Go is a basic promise implementation: it wraps calls a function in a goroutine
|
||||
// and returns a channel which will later return the function's return value.
|
||||
@@ -35,3 +30,53 @@ func CallOrElse(cond bool, okFn, elseFn ErrFunc) error {
|
||||
}
|
||||
return elseFn()
|
||||
}
|
||||
|
||||
// SafeRun sync run a func. If the func panics, the panic value is returned as an error.
|
||||
func SafeRun(fn func()) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if e, ok := r.(error); ok {
|
||||
err = e
|
||||
} else {
|
||||
err = fmt.Errorf("%v", r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
fn()
|
||||
return nil
|
||||
}
|
||||
|
||||
// SafeRun sync run a func with error.
|
||||
// If the func panics, the panic value is returned as an error.
|
||||
func SafeRunWithError(fn func() error) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if e, ok := r.(error); ok {
|
||||
err = e
|
||||
} else {
|
||||
err = fmt.Errorf("%v", r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
return fn()
|
||||
}
|
||||
|
||||
// SafeGo async run a func.
|
||||
// If the func panics, the panic value will be handle by errHandler.
|
||||
func SafeGo(fn func(), errHandler func(error)) {
|
||||
go func() {
|
||||
if err := SafeRun(fn); err != nil {
|
||||
errHandler(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// SafeGoWithError async run a func with error.
|
||||
// If the func panics, the panic value will be handle by errHandler.
|
||||
func SafeGoWithError(fn func() error, errHandler func(error)) {
|
||||
go func() {
|
||||
if err := SafeRunWithError(fn); err != nil {
|
||||
errHandler(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
34
vendor/github.com/gookit/goutil/goinfo/README.md
generated
vendored
Normal file
34
vendor/github.com/gookit/goutil/goinfo/README.md
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
# GoInfo
|
||||
|
||||
`goutil/goinfo` provide some useful info for golang.
|
||||
|
||||
> Github: https://github.com/gookit/goutil
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
go get github.com/gookit/goutil/goinfo
|
||||
```
|
||||
|
||||
## Go docs
|
||||
|
||||
- [Go docs](https://pkg.go.dev/github.com/gookit/goutil)
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
gover := goinfo.GoVersion() // eg: "1.15.6"
|
||||
|
||||
```
|
||||
|
||||
## Testings
|
||||
|
||||
```shell
|
||||
go test -v ./goinfo/...
|
||||
```
|
||||
|
||||
Test limit by regexp:
|
||||
|
||||
```shell
|
||||
go test -v -run ^TestSetByKeys ./goinfo/...
|
||||
```
|
||||
@@ -1,20 +1,21 @@
|
||||
package stdutil
|
||||
package goinfo
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/gookit/goutil/strutil"
|
||||
)
|
||||
|
||||
// FullFcName struct.
|
||||
type FullFcName struct {
|
||||
// FullName eg: github.com/gookit/goutil/stdutil.PanicIf
|
||||
// FullName eg: "github.com/gookit/goutil/goinfo.PanicIf"
|
||||
FullName string
|
||||
pkgPath string
|
||||
pkgName string
|
||||
funcName string
|
||||
pkgPath string // "github.com/gookit/goutil/goinfo"
|
||||
pkgName string // "goinfo"
|
||||
funcName string // "PanicIf"
|
||||
}
|
||||
|
||||
// Parse the full func name.
|
||||
@@ -28,17 +29,16 @@ func (ffn *FullFcName) Parse() {
|
||||
ffn.pkgPath = ffn.FullName[:i+1]
|
||||
// spilt get pkg and func name
|
||||
ffn.pkgName, ffn.funcName = strutil.MustCut(ffn.FullName[i+1:], ".")
|
||||
|
||||
ffn.pkgPath += ffn.pkgName
|
||||
}
|
||||
|
||||
// PkgPath string get. eg: github.com/gookit/goutil/stdutil
|
||||
// PkgPath string get. eg: github.com/gookit/goutil/goinfo
|
||||
func (ffn *FullFcName) PkgPath() string {
|
||||
ffn.Parse()
|
||||
return ffn.pkgPath
|
||||
}
|
||||
|
||||
// PkgName string get. eg: stdutil
|
||||
// PkgName string get. eg: goinfo
|
||||
func (ffn *FullFcName) PkgName() string {
|
||||
ffn.Parse()
|
||||
return ffn.pkgName
|
||||
@@ -50,7 +50,7 @@ func (ffn *FullFcName) FuncName() string {
|
||||
return ffn.funcName
|
||||
}
|
||||
|
||||
// String get full func name string.
|
||||
// String get full func name string, pkg path and func name.
|
||||
func (ffn *FullFcName) String() string {
|
||||
return ffn.FullName
|
||||
}
|
||||
@@ -59,13 +59,16 @@ func (ffn *FullFcName) String() string {
|
||||
//
|
||||
// eg:
|
||||
//
|
||||
// // OUTPUT: github.com/gookit/goutil/stdutil.PanicIf
|
||||
// stdutil.FuncName(stdutil.PkgName)
|
||||
// // OUTPUT: github.com/gookit/goutil/goinfo.PkgName
|
||||
// goinfo.FuncName(goinfo.PkgName)
|
||||
func FuncName(fn any) string {
|
||||
return runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
|
||||
}
|
||||
|
||||
// CutFuncName get pkg path and short func name
|
||||
// eg:
|
||||
//
|
||||
// "github.com/gookit/goutil/goinfo.FuncName" => [github.com/gookit/goutil/goinfo, FuncName]
|
||||
func CutFuncName(fullFcName string) (pkgPath, shortFnName string) {
|
||||
ffn := FullFcName{FullName: fullFcName}
|
||||
return ffn.PkgPath(), ffn.FuncName()
|
||||
@@ -75,12 +78,13 @@ func CutFuncName(fullFcName string) (pkgPath, shortFnName string) {
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// fullFcName := stdutil.FuncName(fn)
|
||||
// pgkName := stdutil.PkgName(fullFcName)
|
||||
// fullFcName := goinfo.FuncName(fn)
|
||||
// pgkName := goinfo.PkgName(fullFcName)
|
||||
func PkgName(fullFcName string) string {
|
||||
for {
|
||||
lastPeriod := strings.LastIndex(fullFcName, ".")
|
||||
lastSlash := strings.LastIndex(fullFcName, "/")
|
||||
|
||||
if lastPeriod > lastSlash {
|
||||
fullFcName = fullFcName[:lastPeriod]
|
||||
} else {
|
||||
@@ -89,3 +93,21 @@ func PkgName(fullFcName string) string {
|
||||
}
|
||||
return fullFcName
|
||||
}
|
||||
|
||||
// GoodFuncName reports whether the function name is a valid identifier.
|
||||
func GoodFuncName(name string) bool {
|
||||
if name == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, r := range name {
|
||||
switch {
|
||||
case r == '_':
|
||||
case i == 0 && !unicode.IsLetter(r):
|
||||
return false
|
||||
case !unicode.IsLetter(r) && !unicode.IsDigit(r):
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
78
vendor/github.com/gookit/goutil/goinfo/goinfo.go
generated
vendored
Normal file
78
vendor/github.com/gookit/goutil/goinfo/goinfo.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
// Package goinfo provide some standard util functions for go.
|
||||
package goinfo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GoVersion get go runtime version. eg: "1.18.2"
|
||||
func GoVersion() string {
|
||||
return runtime.Version()[2:]
|
||||
}
|
||||
|
||||
// GoInfo define
|
||||
//
|
||||
// On os by:
|
||||
//
|
||||
// go env GOVERSION GOOS GOARCH
|
||||
// go version // "go version go1.19 darwin/amd64"
|
||||
type GoInfo struct {
|
||||
Version string
|
||||
GoOS string
|
||||
Arch string
|
||||
}
|
||||
|
||||
// match "go version go1.19 darwin/amd64"
|
||||
var goVerRegex = regexp.MustCompile(`\sgo([\d.]+)\s(\w+)/(\w+)`)
|
||||
|
||||
// ParseGoVersion get info by parse `go version` results.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// line, err := sysutil.ExecLine("go version")
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// info, err := goinfo.ParseGoVersion()
|
||||
// dump.P(info)
|
||||
func ParseGoVersion(line string) (*GoInfo, error) {
|
||||
// eg: [" go1.19 darwin/amd64", "1.19", "darwin", "amd64"]
|
||||
lines := goVerRegex.FindStringSubmatch(line)
|
||||
if len(lines) != 4 {
|
||||
return nil, errors.New("input go version info is invalid")
|
||||
}
|
||||
|
||||
info := &GoInfo{
|
||||
Version: strings.TrimPrefix(lines[1], "go"),
|
||||
}
|
||||
info.GoOS = lines[2]
|
||||
info.Arch = lines[3]
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// OsGoInfo fetch and parse
|
||||
func OsGoInfo() (*GoInfo, error) {
|
||||
cmdArgs := []string{"env", "GOVERSION", "GOOS", "GOARCH"}
|
||||
bs, err := exec.Command("go", cmdArgs...).Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lines := strings.Split(strings.TrimSpace(string(bs)), "\n")
|
||||
if len(lines) != len(cmdArgs)-1 {
|
||||
return nil, errors.New("returns go info is not full")
|
||||
}
|
||||
|
||||
info := &GoInfo{}
|
||||
info.Version = strings.TrimPrefix(lines[0], "go")
|
||||
info.GoOS = lines[1]
|
||||
info.Arch = lines[2]
|
||||
|
||||
return info, nil
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
package stdutil
|
||||
package goinfo
|
||||
|
||||
import (
|
||||
"path"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/basefn"
|
||||
)
|
||||
|
||||
// some commonly consts
|
||||
@@ -42,15 +44,11 @@ func GetCallStacks(all bool) []byte {
|
||||
//
|
||||
// returns:
|
||||
//
|
||||
// github.com/gookit/goutil/stdutil_test.someFunc2(),stack_test.go:26
|
||||
// github.com/gookit/goutil/goinfo_test.someFunc2(),stack_test.go:26
|
||||
func GetCallerInfo(skip int) string {
|
||||
skip++ // ignore current func
|
||||
cs := GetCallersInfo(skip, skip+1)
|
||||
|
||||
if len(cs) > 0 {
|
||||
return cs[0]
|
||||
}
|
||||
return ""
|
||||
return basefn.FirstOr(cs, "")
|
||||
}
|
||||
|
||||
// SimpleCallersInfo returns an array of strings containing
|
||||
@@ -62,6 +60,7 @@ func SimpleCallersInfo(skip, num int) []string {
|
||||
|
||||
// GetCallersInfo returns an array of strings containing
|
||||
// the func name, file and line number of each stack frame leading.
|
||||
//
|
||||
// NOTICE: max should > skip
|
||||
func GetCallersInfo(skip, max int) []string {
|
||||
var (
|
||||
@@ -93,7 +92,7 @@ func GetCallersInfo(skip, max int) []string {
|
||||
if strings.ContainsRune(file, '/') {
|
||||
name = fc.Name()
|
||||
file = path.Base(file)
|
||||
// eg: github.com/gookit/goutil/stdutil_test.someFunc2(),stack_test.go:26
|
||||
// eg: github.com/gookit/goutil/goinfo_test.someFunc2(),stack_test.go:26
|
||||
callers = append(callers, name+"(),"+file+":"+strconv.Itoa(line))
|
||||
}
|
||||
|
||||
22
vendor/github.com/gookit/goutil/goutil.go
generated
vendored
22
vendor/github.com/gookit/goutil/goutil.go
generated
vendored
@@ -5,17 +5,24 @@ package goutil
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gookit/goutil/stdutil"
|
||||
"github.com/gookit/goutil/basefn"
|
||||
"github.com/gookit/goutil/goinfo"
|
||||
"github.com/gookit/goutil/structs"
|
||||
)
|
||||
|
||||
// Value alias of stdutil.Value
|
||||
type Value = stdutil.Value
|
||||
// Value alias of structs.Value
|
||||
type Value = structs.Value
|
||||
|
||||
// Panicf format panic message use fmt.Sprintf
|
||||
func Panicf(format string, v ...any) {
|
||||
panic(fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// PanicIf if cond = true, panics with error message
|
||||
func PanicIf(cond bool, fmtAndArgs ...any) {
|
||||
basefn.PanicIf(cond, fmtAndArgs...)
|
||||
}
|
||||
|
||||
// PanicIfErr if error is not empty, will panic
|
||||
func PanicIfErr(err error) {
|
||||
if err != nil {
|
||||
@@ -45,14 +52,19 @@ func Must[T any](v T, err error) T {
|
||||
return v
|
||||
}
|
||||
|
||||
// PkgName get current package name. alias of stdutil.PkgName()
|
||||
// FuncName get func name
|
||||
func FuncName(f any) string {
|
||||
return goinfo.FuncName(f)
|
||||
}
|
||||
|
||||
// PkgName get current package name. alias of goinfo.PkgName()
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// funcName := goutil.FuncName(fn)
|
||||
// pgkName := goutil.PkgName(funcName)
|
||||
func PkgName(funcName string) string {
|
||||
return stdutil.PkgName(funcName)
|
||||
return goinfo.PkgName(funcName)
|
||||
}
|
||||
|
||||
// ErrOnFail return input error on cond is false, otherwise return nil
|
||||
|
||||
33
vendor/github.com/gookit/goutil/group.go
generated
vendored
33
vendor/github.com/gookit/goutil/group.go
generated
vendored
@@ -4,46 +4,21 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/gookit/goutil/structs"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"github.com/gookit/goutil/syncs"
|
||||
)
|
||||
|
||||
// ErrGroup is a collection of goroutines working on subtasks that
|
||||
// are part of the same overall task.
|
||||
//
|
||||
// Refers:
|
||||
//
|
||||
// https://github.com/neilotoole/errgroup
|
||||
// https://github.com/fatih/semgroup
|
||||
type ErrGroup struct {
|
||||
*errgroup.Group
|
||||
}
|
||||
type ErrGroup = syncs.ErrGroup
|
||||
|
||||
// NewCtxErrGroup instance
|
||||
func NewCtxErrGroup(ctx context.Context, limit ...int) (*ErrGroup, context.Context) {
|
||||
egg, ctx1 := errgroup.WithContext(ctx)
|
||||
if len(limit) > 0 && limit[0] > 0 {
|
||||
egg.SetLimit(limit[0])
|
||||
}
|
||||
|
||||
eg := &ErrGroup{Group: egg}
|
||||
return eg, ctx1
|
||||
return syncs.NewCtxErrGroup(ctx, limit...)
|
||||
}
|
||||
|
||||
// NewErrGroup instance
|
||||
func NewErrGroup(limit ...int) *ErrGroup {
|
||||
eg := &ErrGroup{Group: new(errgroup.Group)}
|
||||
|
||||
if len(limit) > 0 && limit[0] > 0 {
|
||||
eg.SetLimit(limit[0])
|
||||
}
|
||||
return eg
|
||||
}
|
||||
|
||||
// Add one or more handler at once
|
||||
func (g *ErrGroup) Add(handlers ...func() error) {
|
||||
for _, handler := range handlers {
|
||||
g.Go(handler)
|
||||
}
|
||||
return syncs.NewErrGroup(limit...)
|
||||
}
|
||||
|
||||
// RunFn func
|
||||
|
||||
78
vendor/github.com/gookit/goutil/internal/checkfn/check.go
generated
vendored
Normal file
78
vendor/github.com/gookit/goutil/internal/checkfn/check.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
package checkfn
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/reflects"
|
||||
)
|
||||
|
||||
// IsNil value check
|
||||
func IsNil(v any) bool {
|
||||
if v == nil {
|
||||
return true
|
||||
}
|
||||
return reflects.IsNil(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
// IsEmpty value check
|
||||
func IsEmpty(v any) bool {
|
||||
if v == nil {
|
||||
return true
|
||||
}
|
||||
return reflects.IsEmpty(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
// Contains try loop over the data check if the data includes the element.
|
||||
//
|
||||
// data allow types: string, map, array, slice
|
||||
//
|
||||
// map - check key exists
|
||||
// string - check sub-string exists
|
||||
// array,slice - check sub-element exists
|
||||
//
|
||||
// Returns:
|
||||
// - valid: data is valid
|
||||
// - found: element was found
|
||||
//
|
||||
// return (false, false) if impossible.
|
||||
// return (true, false) if element was not found.
|
||||
// return (true, true) if element was found.
|
||||
func Contains(data, elem any) (valid, found bool) {
|
||||
if data == nil {
|
||||
return false, false
|
||||
}
|
||||
|
||||
dataRv := reflect.ValueOf(data)
|
||||
dataRt := reflect.TypeOf(data)
|
||||
dataKind := dataRt.Kind()
|
||||
|
||||
// string
|
||||
if dataKind == reflect.String {
|
||||
return true, strings.Contains(dataRv.String(), fmt.Sprint(elem))
|
||||
}
|
||||
|
||||
// map
|
||||
if dataKind == reflect.Map {
|
||||
mapKeys := dataRv.MapKeys()
|
||||
for i := 0; i < len(mapKeys); i++ {
|
||||
if reflects.IsEqual(mapKeys[i].Interface(), elem) {
|
||||
return true, true
|
||||
}
|
||||
}
|
||||
return true, false
|
||||
}
|
||||
|
||||
// array, slice - other return false
|
||||
if dataKind != reflect.Slice && dataKind != reflect.Array {
|
||||
return false, false
|
||||
}
|
||||
|
||||
for i := 0; i < dataRv.Len(); i++ {
|
||||
if reflects.IsEqual(dataRv.Index(i).Interface(), elem) {
|
||||
return true, true
|
||||
}
|
||||
}
|
||||
return true, false
|
||||
}
|
||||
3
vendor/github.com/gookit/goutil/internal/comfunc/README.md
generated
vendored
Normal file
3
vendor/github.com/gookit/goutil/internal/comfunc/README.md
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# common func for internal use
|
||||
|
||||
- don't depend on other external packages
|
||||
90
vendor/github.com/gookit/goutil/internal/comfunc/comfunc.go
generated
vendored
90
vendor/github.com/gookit/goutil/internal/comfunc/comfunc.go
generated
vendored
@@ -26,90 +26,14 @@ func Environ() map[string]string {
|
||||
return envMap
|
||||
}
|
||||
|
||||
// parse env value, allow:
|
||||
//
|
||||
// only key - "${SHELL}"
|
||||
// with default - "${NotExist | defValue}"
|
||||
// multi key - "${GOPATH}/${APP_ENV | prod}/dir"
|
||||
//
|
||||
// Notice:
|
||||
//
|
||||
// must add "?" - To ensure that there is no greedy match
|
||||
// var envRegex = regexp.MustCompile(`\${[\w-| ]+}`)
|
||||
var envRegex = regexp.MustCompile(`\${.+?}`)
|
||||
|
||||
// ParseEnvVar parse ENV var value from input string, support default value.
|
||||
//
|
||||
// Format:
|
||||
//
|
||||
// ${var_name} Only var name
|
||||
// ${var_name | default} With default value
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// comfunc.ParseEnvVar("${ APP_NAME }")
|
||||
// comfunc.ParseEnvVar("${ APP_ENV | dev }")
|
||||
func ParseEnvVar(val string, getFn func(string) string) (newVal string) {
|
||||
if !strings.Contains(val, "${") {
|
||||
return val
|
||||
}
|
||||
|
||||
// default use os.Getenv
|
||||
if getFn == nil {
|
||||
getFn = os.Getenv
|
||||
}
|
||||
|
||||
var name, def string
|
||||
return envRegex.ReplaceAllStringFunc(val, func(eVar string) string {
|
||||
// eVar like "${NotExist|defValue}", first remove "${" and "}", then split it
|
||||
ss := strings.SplitN(eVar[2:len(eVar)-1], "|", 2)
|
||||
|
||||
// with default value. ${NotExist|defValue}
|
||||
if len(ss) == 2 {
|
||||
name, def = strings.TrimSpace(ss[0]), strings.TrimSpace(ss[1])
|
||||
} else {
|
||||
name = strings.TrimSpace(ss[0])
|
||||
}
|
||||
|
||||
// get ENV value by name
|
||||
eVal := getFn(name)
|
||||
if eVal == "" {
|
||||
eVal = def
|
||||
}
|
||||
return eVal
|
||||
})
|
||||
}
|
||||
|
||||
// FormatTplAndArgs message
|
||||
func FormatTplAndArgs(fmtAndArgs []any) string {
|
||||
if len(fmtAndArgs) == 0 || fmtAndArgs == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
ln := len(fmtAndArgs)
|
||||
first := fmtAndArgs[0]
|
||||
|
||||
if ln == 1 {
|
||||
if msgAsStr, ok := first.(string); ok {
|
||||
return msgAsStr
|
||||
}
|
||||
return fmt.Sprintf("%+v", first)
|
||||
}
|
||||
|
||||
// is template string.
|
||||
if tplStr, ok := first.(string); ok {
|
||||
return fmt.Sprintf(tplStr, fmtAndArgs[1:]...)
|
||||
}
|
||||
return fmt.Sprint(fmtAndArgs...)
|
||||
}
|
||||
|
||||
var (
|
||||
// TIP: extend unit d,w
|
||||
// time.ParseDuration() is not supported. eg: "1d", "2w"
|
||||
// TIP: extend unit d,w. eg: "1d", "2w"
|
||||
// time.ParseDuration() is max support hour "h".
|
||||
durStrReg = regexp.MustCompile(`^(-?\d+)(ns|us|µs|ms|s|m|h|d|w)$`)
|
||||
// match long duration string, such as "1hour", "2hours", "3minutes", "4mins", "5days", "1weeks"
|
||||
|
||||
// match long duration string. eg: "1hour", "2hours", "3minutes", "4mins", "5days", "1weeks", "1month"
|
||||
// time.ParseDuration() is not supported.
|
||||
durStrRegL = regexp.MustCompile(`^(-?\d+)([a-zA-Z]{3,})$`)
|
||||
durStrRegL = regexp.MustCompile(`^(-?\d+)([hdmsw][a-zA-Z]{2,8})$`)
|
||||
)
|
||||
|
||||
// IsDuration check the string is a duration string.
|
||||
@@ -153,6 +77,10 @@ func ToDuration(s string) (time.Duration, error) {
|
||||
|
||||
// convert to short unit
|
||||
switch unit {
|
||||
case "month", "months":
|
||||
// max unit is hour, so need convert by 24 * 30 * n
|
||||
n, _ := strconv.Atoi(num)
|
||||
s = strconv.Itoa(n*24*30) + "h"
|
||||
case "week", "weeks":
|
||||
// max unit is hour, so need convert by 24 * 7 * n
|
||||
n, _ := strconv.Atoi(num)
|
||||
|
||||
23
vendor/github.com/gookit/goutil/internal/comfunc/convert.go
generated
vendored
23
vendor/github.com/gookit/goutil/internal/comfunc/convert.go
generated
vendored
@@ -37,3 +37,26 @@ func StrToBool(s string) (bool, error) {
|
||||
|
||||
return false, fmt.Errorf("'%s' cannot convert to bool", s)
|
||||
}
|
||||
|
||||
// FormatWithArgs format message with args
|
||||
func FormatWithArgs(fmtAndArgs []any) string {
|
||||
ln := len(fmtAndArgs)
|
||||
if ln == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
first := fmtAndArgs[0]
|
||||
|
||||
if ln == 1 {
|
||||
if msgAsStr, ok := first.(string); ok {
|
||||
return msgAsStr
|
||||
}
|
||||
return fmt.Sprintf("%+v", first)
|
||||
}
|
||||
|
||||
// is template string.
|
||||
if tplStr, ok := first.(string); ok {
|
||||
return fmt.Sprintf(tplStr, fmtAndArgs[1:]...)
|
||||
}
|
||||
return fmt.Sprint(fmtAndArgs...)
|
||||
}
|
||||
|
||||
145
vendor/github.com/gookit/goutil/internal/varexpr/varexpr.go
generated
vendored
Normal file
145
vendor/github.com/gookit/goutil/internal/varexpr/varexpr.go
generated
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
// Package varexpr provides some commonly ENV var parse functions.
|
||||
//
|
||||
// parse env value, allow expressions:
|
||||
//
|
||||
// ${VAR_NAME} Only var name
|
||||
// ${VAR_NAME | default} With default value, if value is empty.
|
||||
// ${VAR_NAME | ?error} With error on value is empty.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// only key - "${SHELL}"
|
||||
// with default - "${NotExist | defValue}"
|
||||
// multi key - "${GOPATH}/${APP_ENV | prod}/dir"
|
||||
package varexpr
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SepChar separator char
|
||||
const SepChar = "|"
|
||||
|
||||
// ParseOptFn option func
|
||||
type ParseOptFn func(o *ParseOpts)
|
||||
|
||||
// ParseOpts parse options for ParseValue
|
||||
type ParseOpts struct {
|
||||
// Getter Env value provider func.
|
||||
Getter func(string) string
|
||||
// ParseFn custom parse expr func. expr like "${SHELL}" "${NotExist|defValue}"
|
||||
ParseFn func(string) (string, error)
|
||||
// Regexp custom expression regex.
|
||||
Regexp *regexp.Regexp
|
||||
// Keyword check chars for expression. default is "${"
|
||||
Keyword string
|
||||
}
|
||||
|
||||
// must add "?" - To ensure that there is no greedy match
|
||||
var envRegex = regexp.MustCompile(`\${.+?}`)
|
||||
var std = New()
|
||||
|
||||
// Parse parse ENV var value from input string, support default value.
|
||||
//
|
||||
// Format:
|
||||
//
|
||||
// ${var_name} Only var name
|
||||
// ${var_name | default} With default value
|
||||
// ${var_name | ?error} With error on value is empty.
|
||||
func Parse(val string) (string, error) {
|
||||
return std.Parse(val)
|
||||
}
|
||||
|
||||
// SafeParse parse ENV var value from input string, support default value.
|
||||
func SafeParse(val string) string {
|
||||
s, _ := std.Parse(val)
|
||||
return s
|
||||
}
|
||||
|
||||
// ParseWith parse ENV var value from input string, support default value.
|
||||
func ParseWith(val string, optFns ...ParseOptFn) (string, error) {
|
||||
return New(optFns...).Parse(val)
|
||||
}
|
||||
|
||||
// Parser parse ENV var value from input string, support default value.
|
||||
type Parser struct {
|
||||
ParseOpts
|
||||
}
|
||||
|
||||
// New create a new Parser
|
||||
func New(optFns ...ParseOptFn) *Parser {
|
||||
opts := &ParseOpts{
|
||||
Getter: os.Getenv,
|
||||
Regexp: envRegex,
|
||||
Keyword: "${",
|
||||
}
|
||||
for _, fn := range optFns {
|
||||
fn(opts)
|
||||
}
|
||||
|
||||
return &Parser{ParseOpts: *opts}
|
||||
}
|
||||
|
||||
// Parse parse ENV var value from input string, support default value.
|
||||
//
|
||||
// Format:
|
||||
//
|
||||
// ${var_name} Only var name
|
||||
// ${var_name | default} With default value
|
||||
// ${var_name | ?error} With error on value is empty.
|
||||
func (p *Parser) Parse(val string) (newVal string, err error) {
|
||||
if p.Regexp == nil {
|
||||
p.Regexp = envRegex
|
||||
}
|
||||
|
||||
if p.Keyword != "" && !strings.Contains(val, p.Keyword) {
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// parse expression
|
||||
newVal = p.Regexp.ReplaceAllStringFunc(val, func(s string) string {
|
||||
if err != nil {
|
||||
return s
|
||||
}
|
||||
s, err = p.parseOne(s)
|
||||
return s
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// parse one node expression.
|
||||
func (p *Parser) parseOne(eVar string) (val string, err error) {
|
||||
if p.ParseFn != nil {
|
||||
return p.ParseFn(eVar)
|
||||
}
|
||||
|
||||
// eVar like "${NotExist|defValue}", first remove "${" and "}", then split it
|
||||
ss := strings.SplitN(eVar[2:len(eVar)-1], SepChar, 2)
|
||||
var name, def string
|
||||
|
||||
// with default value. ${NotExist|defValue}
|
||||
if len(ss) == 2 {
|
||||
name, def = strings.TrimSpace(ss[0]), strings.TrimSpace(ss[1])
|
||||
} else {
|
||||
name = strings.TrimSpace(ss[0])
|
||||
}
|
||||
|
||||
// get ENV value by name
|
||||
val = p.Getter(name)
|
||||
if val == "" && def != "" {
|
||||
// check def is "?error"
|
||||
if def[0] == '?' {
|
||||
msg := "value is required for var: " + name
|
||||
if len(def) > 1 {
|
||||
msg = def[1:]
|
||||
}
|
||||
err = errors.New(msg)
|
||||
} else {
|
||||
val = def
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
64
vendor/github.com/gookit/goutil/jsonutil/encoding.go
generated
vendored
Normal file
64
vendor/github.com/gookit/goutil/jsonutil/encoding.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
package jsonutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
)
|
||||
|
||||
// MustString encode data to json string, will panic on error
|
||||
func MustString(v any) string {
|
||||
bs, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(bs)
|
||||
}
|
||||
|
||||
// Encode data to json bytes. alias of json.Marshal
|
||||
func Encode(v any) ([]byte, error) {
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
// EncodePretty encode data to pretty JSON bytes.
|
||||
func EncodePretty(v any) ([]byte, error) {
|
||||
return json.MarshalIndent(v, "", " ")
|
||||
}
|
||||
|
||||
// EncodeString encode data to JSON string.
|
||||
func EncodeString(v any) (string, error) {
|
||||
bs, err := json.MarshalIndent(v, "", " ")
|
||||
return string(bs), err
|
||||
}
|
||||
|
||||
// EncodeToWriter encode data to json and write to writer.
|
||||
func EncodeToWriter(v any, w io.Writer) error {
|
||||
return json.NewEncoder(w).Encode(v)
|
||||
}
|
||||
|
||||
// EncodeUnescapeHTML data to json bytes. will close escape HTML
|
||||
func EncodeUnescapeHTML(v any) ([]byte, error) {
|
||||
buf := &bytes.Buffer{}
|
||||
enc := json.NewEncoder(buf)
|
||||
enc.SetEscapeHTML(false)
|
||||
|
||||
if err := enc.Encode(v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// Decode json bytes to data ptr. alias of json.Unmarshal
|
||||
func Decode(bts []byte, ptr any) error {
|
||||
return json.Unmarshal(bts, ptr)
|
||||
}
|
||||
|
||||
// DecodeString json string to data ptr.
|
||||
func DecodeString(str string, ptr any) error {
|
||||
return json.Unmarshal([]byte(str), ptr)
|
||||
}
|
||||
|
||||
// DecodeReader decode JSON from io reader.
|
||||
func DecodeReader(r io.Reader, ptr any) error {
|
||||
return json.NewDecoder(r).Decode(ptr)
|
||||
}
|
||||
21
vendor/github.com/gookit/goutil/jsonutil/jsonbuild.go
generated
vendored
Normal file
21
vendor/github.com/gookit/goutil/jsonutil/jsonbuild.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
package jsonutil
|
||||
|
||||
/*
|
||||
TODO json build
|
||||
type JsonBuilder struct {
|
||||
Indent string
|
||||
// mu sync.Mutex
|
||||
// cfg *CConfig
|
||||
buf bytes.Buffer
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
// AddField add field to json
|
||||
func (b *JsonBuilder) AddField(key string, value any) *JsonBuilder {
|
||||
b.buf.WriteString(`,"`)
|
||||
b.buf.WriteString(key)
|
||||
b.buf.WriteString(`":`)
|
||||
b.encode(value)
|
||||
return b
|
||||
}
|
||||
*/
|
||||
85
vendor/github.com/gookit/goutil/jsonutil/jsonutil.go
generated
vendored
85
vendor/github.com/gookit/goutil/jsonutil/jsonutil.go
generated
vendored
@@ -4,7 +4,6 @@ package jsonutil
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -13,7 +12,7 @@ import (
|
||||
|
||||
// WriteFile write data to JSON file
|
||||
func WriteFile(filePath string, data any) error {
|
||||
jsonBytes, err := Encode(data)
|
||||
jsonBytes, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -46,71 +45,35 @@ func Pretty(v any) (string, error) {
|
||||
return string(out), err
|
||||
}
|
||||
|
||||
// Encode data to json bytes.
|
||||
func Encode(v any) ([]byte, error) {
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
// EncodePretty encode pretty JSON data to json bytes.
|
||||
func EncodePretty(v any) ([]byte, error) {
|
||||
return json.MarshalIndent(v, "", " ")
|
||||
}
|
||||
|
||||
// EncodeToWriter encode data to writer.
|
||||
func EncodeToWriter(v any, w io.Writer) error {
|
||||
return json.NewEncoder(w).Encode(v)
|
||||
}
|
||||
|
||||
// EncodeUnescapeHTML data to json bytes. will close escape HTML
|
||||
func EncodeUnescapeHTML(v any) ([]byte, error) {
|
||||
buf := &bytes.Buffer{}
|
||||
enc := json.NewEncoder(buf)
|
||||
enc.SetEscapeHTML(false)
|
||||
|
||||
if err := enc.Encode(v); err != nil {
|
||||
return nil, err
|
||||
// MustPretty data to JSON string, will panic on error
|
||||
func MustPretty(v any) string {
|
||||
out, err := json.MarshalIndent(v, "", " ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// Decode json bytes to data ptr.
|
||||
func Decode(bts []byte, ptr any) error {
|
||||
return json.Unmarshal(bts, ptr)
|
||||
}
|
||||
|
||||
// DecodeString json string to data ptr.
|
||||
func DecodeString(str string, ptr any) error {
|
||||
return json.Unmarshal([]byte(str), ptr)
|
||||
}
|
||||
|
||||
// DecodeReader decode JSON from io reader.
|
||||
func DecodeReader(r io.Reader, ptr any) error {
|
||||
return json.NewDecoder(r).Decode(ptr)
|
||||
return string(out)
|
||||
}
|
||||
|
||||
// Mapping src data(map,struct) to dst struct use json tags.
|
||||
//
|
||||
// On src, dst both is struct, equivalent to merging two structures (src should be a subset of dsc)
|
||||
func Mapping(src, dst any) error {
|
||||
bts, err := Encode(src)
|
||||
bts, err := json.Marshal(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return Decode(bts, dst)
|
||||
}
|
||||
|
||||
// IsJSON check if the string is valid JSON. (Note: uses json.Unmarshal)
|
||||
// IsJSON check if the string is valid JSON. (Note: uses json.Valid)
|
||||
func IsJSON(s string) bool {
|
||||
if s == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
var js json.RawMessage
|
||||
return json.Unmarshal([]byte(s), &js) == nil
|
||||
return json.Valid([]byte(s))
|
||||
}
|
||||
|
||||
// IsJSONFast simple and fast check input string is valid JSON.
|
||||
// IsJSONFast simple and fast check input is valid JSON array or object.
|
||||
func IsJSONFast(s string) bool {
|
||||
ln := len(s)
|
||||
if ln < 2 {
|
||||
@@ -129,6 +92,32 @@ func IsJSONFast(s string) bool {
|
||||
return s[0] == '[' && s[ln-1] == ']'
|
||||
}
|
||||
|
||||
// IsArray check if the string is valid JSON array.
|
||||
func IsArray(s string) bool {
|
||||
ln := len(s)
|
||||
if ln < 2 {
|
||||
return false
|
||||
}
|
||||
return s[0] == '[' && s[ln-1] == ']'
|
||||
}
|
||||
|
||||
// IsObject check if the string is valid JSON object.
|
||||
func IsObject(s string) bool {
|
||||
ln := len(s)
|
||||
if ln < 2 {
|
||||
return false
|
||||
}
|
||||
if ln == 2 {
|
||||
return s == "{}"
|
||||
}
|
||||
|
||||
// object
|
||||
if s[0] == '{' {
|
||||
return s[ln-1] == '}' && s[1] == '"'
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// `(?s:` enable match multi line
|
||||
var jsonMLComments = regexp.MustCompile(`(?s:/\*.*?\*/\s*)`)
|
||||
|
||||
|
||||
6
vendor/github.com/gookit/goutil/maputil/alias.go
generated
vendored
6
vendor/github.com/gookit/goutil/maputil/alias.go
generated
vendored
@@ -6,7 +6,7 @@ import "fmt"
|
||||
type Aliases map[string]string
|
||||
|
||||
// AddAlias to the Aliases
|
||||
func (as Aliases) AddAlias(real, alias string) {
|
||||
func (as Aliases) AddAlias(alias, real string) {
|
||||
if rn, ok := as[alias]; ok {
|
||||
panic(fmt.Sprintf("The alias '%s' is already used by '%s'", alias, rn))
|
||||
}
|
||||
@@ -16,14 +16,14 @@ func (as Aliases) AddAlias(real, alias string) {
|
||||
// AddAliases to the Aliases
|
||||
func (as Aliases) AddAliases(real string, aliases []string) {
|
||||
for _, a := range aliases {
|
||||
as.AddAlias(real, a)
|
||||
as.AddAlias(a, real)
|
||||
}
|
||||
}
|
||||
|
||||
// AddAliasMap to the Aliases
|
||||
func (as Aliases) AddAliasMap(alias2real map[string]string) {
|
||||
for a, r := range alias2real {
|
||||
as.AddAlias(r, a)
|
||||
as.AddAlias(a, r)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
5
vendor/github.com/gookit/goutil/maputil/data.go
generated
vendored
5
vendor/github.com/gookit/goutil/maputil/data.go
generated
vendored
@@ -188,10 +188,7 @@ func (d Data) StrSplit(key, sep string) []string {
|
||||
|
||||
// StringsByStr value get by key
|
||||
func (d Data) StringsByStr(key string) []string {
|
||||
if val, ok := d.GetByPath(key); ok {
|
||||
return strings.Split(strutil.QuietString(val), ",")
|
||||
}
|
||||
return nil
|
||||
return d.StrSplit(key, ",")
|
||||
}
|
||||
|
||||
// StrMap get map[string]string value
|
||||
|
||||
8
vendor/github.com/gookit/goutil/maputil/format.go
generated
vendored
8
vendor/github.com/gookit/goutil/maputil/format.go
generated
vendored
@@ -92,16 +92,16 @@ func (f *MapFormatter) doFormat() {
|
||||
}
|
||||
|
||||
for i, key := range rv.MapKeys() {
|
||||
kStr := strutil.QuietString(key.Interface())
|
||||
strK := strutil.SafeString(key.Interface())
|
||||
if indentLn > 0 {
|
||||
buf.WriteString(f.Indent)
|
||||
}
|
||||
|
||||
buf.WriteString(kStr)
|
||||
buf.WriteString(strK)
|
||||
buf.WriteByte(':')
|
||||
|
||||
vStr := strutil.QuietString(rv.MapIndex(key).Interface())
|
||||
buf.WriteString(vStr)
|
||||
strV := strutil.SafeString(rv.MapIndex(key).Interface())
|
||||
buf.WriteString(strV)
|
||||
if i < ln-1 {
|
||||
buf.WriteByte(',')
|
||||
|
||||
|
||||
89
vendor/github.com/gookit/goutil/maputil/get.go
generated
vendored
89
vendor/github.com/gookit/goutil/maputil/get.go
generated
vendored
@@ -4,6 +4,8 @@ import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/goutil/reflects"
|
||||
)
|
||||
|
||||
// some consts for separators
|
||||
@@ -24,8 +26,24 @@ func QuietGet(mp map[string]any, path string) (val any) {
|
||||
return
|
||||
}
|
||||
|
||||
// GetFromAny get value by key path from any(map,slice) data. eg "top" "top.sub"
|
||||
func GetFromAny(path string, data any) (val any, ok bool) {
|
||||
// empty data
|
||||
if data == nil {
|
||||
return nil, false
|
||||
}
|
||||
if len(path) == 0 {
|
||||
return data, true
|
||||
}
|
||||
|
||||
return getByPathKeys(data, strings.Split(path, "."))
|
||||
}
|
||||
|
||||
// GetByPath get value by key path from a map(map[string]any). eg "top" "top.sub"
|
||||
func GetByPath(path string, mp map[string]any) (val any, ok bool) {
|
||||
if len(path) == 0 {
|
||||
return mp, true
|
||||
}
|
||||
if val, ok := mp[path]; ok {
|
||||
return val, true
|
||||
}
|
||||
@@ -35,9 +53,8 @@ func GetByPath(path string, mp map[string]any) (val any, ok bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// has sub key. eg. "top.sub"
|
||||
keys := strings.Split(path, ".")
|
||||
return GetByPathKeys(mp, keys)
|
||||
// key is path. eg: "top.sub"
|
||||
return GetByPathKeys(mp, strings.Split(path, "."))
|
||||
}
|
||||
|
||||
// GetByPathKeys get value by path keys from a map(map[string]any). eg "top" "top.sub"
|
||||
@@ -58,14 +75,19 @@ func GetByPathKeys(mp map[string]any, keys []string) (val any, ok bool) {
|
||||
|
||||
// find top item data use top key
|
||||
var item any
|
||||
|
||||
topK := keys[0]
|
||||
if item, ok = mp[topK]; !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// find sub item data use sub key
|
||||
for i, k := range keys[1:] {
|
||||
return getByPathKeys(item, keys[1:])
|
||||
}
|
||||
|
||||
func getByPathKeys(item any, keys []string) (val any, ok bool) {
|
||||
kl := len(keys)
|
||||
|
||||
for i, k := range keys {
|
||||
switch tData := item.(type) {
|
||||
case map[string]string: // is string map
|
||||
if item, ok = tData[k]; !ok {
|
||||
@@ -81,48 +103,77 @@ func GetByPathKeys(mp map[string]any, keys []string) (val any, ok bool) {
|
||||
}
|
||||
case []map[string]any: // is an any-map slice
|
||||
if k == Wildcard {
|
||||
if kl == i+2 {
|
||||
if kl == i+1 { // * is last key
|
||||
return tData, true
|
||||
}
|
||||
|
||||
// * is not last key, find sub item data
|
||||
sl := make([]any, 0, len(tData))
|
||||
for _, v := range tData {
|
||||
if val, ok = GetByPathKeys(v, keys[i+2:]); ok {
|
||||
if val, ok = getByPathKeys(v, keys[i+1:]); ok {
|
||||
sl = append(sl, val)
|
||||
}
|
||||
}
|
||||
return sl, true
|
||||
|
||||
if len(sl) > 0 {
|
||||
return sl, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// k is index number
|
||||
idx, err := strconv.Atoi(k)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if idx >= len(tData) {
|
||||
if err != nil || idx >= len(tData) {
|
||||
return nil, false
|
||||
}
|
||||
item = tData[idx]
|
||||
default:
|
||||
if k == Wildcard && kl == i+1 { // * is last key
|
||||
return tData, true
|
||||
}
|
||||
|
||||
rv := reflect.ValueOf(tData)
|
||||
// check is slice
|
||||
if rv.Kind() == reflect.Slice {
|
||||
i, err := strconv.Atoi(k)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
if i >= rv.Len() {
|
||||
if k == Wildcard {
|
||||
// * is not last key, find sub item data
|
||||
sl := make([]any, 0, rv.Len())
|
||||
for si := 0; si < rv.Len(); si++ {
|
||||
el := reflects.Indirect(rv.Index(si))
|
||||
if el.Kind() != reflect.Map {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// el is map value.
|
||||
if val, ok = getByPathKeys(el.Interface(), keys[i+1:]); ok {
|
||||
sl = append(sl, val)
|
||||
}
|
||||
}
|
||||
|
||||
if len(sl) > 0 {
|
||||
return sl, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
item = rv.Index(i).Interface()
|
||||
// check k is index number
|
||||
ii, err := strconv.Atoi(k)
|
||||
if err != nil || ii >= rv.Len() {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
item = rv.Index(ii).Interface()
|
||||
continue
|
||||
}
|
||||
|
||||
// as error
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// next is last key and it is *
|
||||
if kl == i+2 && keys[i+1] == Wildcard {
|
||||
return item, true
|
||||
}
|
||||
}
|
||||
|
||||
return item, true
|
||||
|
||||
12
vendor/github.com/gookit/goutil/maputil/smap.go
generated
vendored
12
vendor/github.com/gookit/goutil/maputil/smap.go
generated
vendored
@@ -29,6 +29,18 @@ func (m SMap) HasValue(val string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Load data to the map
|
||||
func (m SMap) Load(data map[string]string) {
|
||||
for k, v := range data {
|
||||
m[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// Set value to the data map
|
||||
func (m SMap) Set(key string, val any) {
|
||||
m[key] = strutil.MustString(val)
|
||||
}
|
||||
|
||||
// Value get from the data map
|
||||
func (m SMap) Value(key string) (string, bool) {
|
||||
val, ok := m[key]
|
||||
|
||||
82
vendor/github.com/gookit/goutil/mathutil/README.md
generated
vendored
82
vendor/github.com/gookit/goutil/mathutil/README.md
generated
vendored
@@ -10,11 +10,91 @@ go get github.com/gookit/goutil/mathutil
|
||||
|
||||
## Go docs
|
||||
|
||||
- [Go docs](https://pkg.go.dev/github.com/gookit/goutil/mathutil)
|
||||
- [Go Docs](https://pkg.go.dev/github.com/gookit/goutil)
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
## Functions
|
||||
|
||||
```go
|
||||
|
||||
func CompFloat[T comdef.Float](first, second T, op string) (ok bool)
|
||||
func CompInt[T comdef.Xint](first, second T, op string) (ok bool)
|
||||
func CompInt64(first, second int64, op string) bool
|
||||
func CompValue[T comdef.XintOrFloat](first, second T, op string) (ok bool)
|
||||
func Compare(first, second any, op string) (ok bool)
|
||||
func DataSize(size uint64) string
|
||||
func ElapsedTime(startTime time.Time) string
|
||||
func Float(in any) (float64, error)
|
||||
func FloatOr(in any, defVal float64) float64
|
||||
func FloatOrDefault(in any, defVal float64) float64
|
||||
func FloatOrErr(in any) (float64, error)
|
||||
func FloatOrPanic(in any) float64
|
||||
func GreaterOr[T comdef.XintOrFloat](val, min, defVal T) T
|
||||
func GteOr[T comdef.XintOrFloat](val, min, defVal T) T
|
||||
func HowLongAgo(sec int64) string
|
||||
func InRange[T comdef.IntOrFloat](val, min, max T) bool
|
||||
func InUintRange[T comdef.Uint](val, min, max T) bool
|
||||
func Int(in any) (int, error)
|
||||
func Int64(in any) (int64, error)
|
||||
func Int64OrErr(in any) (int64, error)
|
||||
func IntOr(in any, defVal int) int
|
||||
func IntOrDefault(in any, defVal int) int
|
||||
func IntOrErr(in any) (iVal int, err error)
|
||||
func IntOrPanic(in any) int
|
||||
func IsNumeric(c byte) bool
|
||||
func LessOr[T comdef.XintOrFloat](val, max, devVal T) T
|
||||
func LteOr[T comdef.XintOrFloat](val, max, devVal T) T
|
||||
func Max[T comdef.XintOrFloat](x, y T) T
|
||||
func MaxFloat(x, y float64) float64
|
||||
func MaxI64(x, y int64) int64
|
||||
func MaxInt(x, y int) int
|
||||
func Min[T comdef.XintOrFloat](x, y T) T
|
||||
func MustFloat(in any) float64
|
||||
func MustInt(in any) int
|
||||
func MustInt64(in any) int64
|
||||
func MustString(val any) string
|
||||
func MustUint(in any) uint64
|
||||
func OrElse[T comdef.XintOrFloat](val, defVal T) T
|
||||
func OutRange[T comdef.IntOrFloat](val, min, max T) bool
|
||||
func Percent(val, total int) float64
|
||||
func QuietFloat(in any) float64
|
||||
func QuietInt(in any) int
|
||||
func QuietInt64(in any) int64
|
||||
func QuietString(val any) string
|
||||
func QuietUint(in any) uint64
|
||||
func RandInt(min, max int) int
|
||||
func RandIntWithSeed(min, max int, seed int64) int
|
||||
func RandomInt(min, max int) int
|
||||
func RandomIntWithSeed(min, max int, seed int64) int
|
||||
func SafeFloat(in any) float64
|
||||
func SafeInt(in any) int
|
||||
func SafeInt64(in any) int64
|
||||
func SafeUint(in any) uint64
|
||||
func StrInt(s string) int
|
||||
func StrIntOr(s string, defVal int) int
|
||||
func String(val any) string
|
||||
func StringOrErr(val any) (string, error)
|
||||
func StringOrPanic(val any) string
|
||||
func SwapMax[T comdef.XintOrFloat](x, y T) (T, T)
|
||||
func SwapMaxI64(x, y int64) (int64, int64)
|
||||
func SwapMaxInt(x, y int) (int, int)
|
||||
func SwapMin[T comdef.XintOrFloat](x, y T) (T, T)
|
||||
func ToFloat(in any) (f64 float64, err error)
|
||||
func ToFloatWithFunc(in any, usrFn func(any) (float64, error)) (f64 float64, err error)
|
||||
func ToInt(in any) (iVal int, err error)
|
||||
func ToInt64(in any) (i64 int64, err error)
|
||||
func ToString(val any) (string, error)
|
||||
func ToUint(in any) (u64 uint64, err error)
|
||||
func ToUintWithFunc(in any, usrFn func(any) (uint64, error)) (u64 uint64, err error)
|
||||
func TryToString(val any, defaultAsErr bool) (str string, err error)
|
||||
func Uint(in any) (uint64, error)
|
||||
func UintOrErr(in any) (uint64, error)
|
||||
func ZeroOr[T comdef.XintOrFloat](val, defVal T) T
|
||||
|
||||
```
|
||||
|
||||
## Testings
|
||||
|
||||
```shell
|
||||
|
||||
82
vendor/github.com/gookit/goutil/mathutil/check.go
generated
vendored
82
vendor/github.com/gookit/goutil/mathutil/check.go
generated
vendored
@@ -2,7 +2,12 @@ package mathutil
|
||||
|
||||
import "github.com/gookit/goutil/comdef"
|
||||
|
||||
// Compare any intX,floatX value by given op. returns `srcVal op(=,!=,<,<=,>,>=) dstVal`
|
||||
// IsNumeric returns true if the given character is a numeric, otherwise false.
|
||||
func IsNumeric(c byte) bool {
|
||||
return c >= '0' && c <= '9'
|
||||
}
|
||||
|
||||
// Compare any intX,floatX value by given op. returns `first op(=,!=,<,<=,>,>=) second`
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
@@ -10,70 +15,61 @@ import "github.com/gookit/goutil/comdef"
|
||||
// mathutil.Compare(2, 1.3, ">") // true
|
||||
// mathutil.Compare(2.2, 1.3, ">") // true
|
||||
// mathutil.Compare(2.1, 2, ">") // true
|
||||
func Compare(srcVal, dstVal any, op string) (ok bool) {
|
||||
if srcVal == nil || dstVal == nil {
|
||||
func Compare(first, second any, op string) bool {
|
||||
if first == nil || second == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// float
|
||||
if srcFlt, ok := srcVal.(float64); ok {
|
||||
if dstFlt, err := ToFloat(dstVal); err == nil {
|
||||
return CompFloat(srcFlt, dstFlt, op)
|
||||
switch fVal := first.(type) {
|
||||
case float64:
|
||||
if sVal, err := ToFloat(second); err == nil {
|
||||
return CompFloat(fVal, sVal, op)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if srcFlt, ok := srcVal.(float32); ok {
|
||||
if dstFlt, err := ToFloat(dstVal); err == nil {
|
||||
return CompFloat(float64(srcFlt), dstFlt, op)
|
||||
case float32:
|
||||
if sVal, err := ToFloat(second); err == nil {
|
||||
return CompFloat(float64(fVal), sVal, op)
|
||||
}
|
||||
default: // as int64
|
||||
if int1, err := ToInt64(first); err == nil {
|
||||
if int2, err := ToInt64(second); err == nil {
|
||||
return CompInt64(int1, int2, op)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// as int64
|
||||
srcInt, err := ToInt64(srcVal)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
dstInt, err := ToInt64(dstVal)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return CompInt64(srcInt, dstInt, op)
|
||||
return false
|
||||
}
|
||||
|
||||
// CompInt compare int,uint value. returns `srcVal op(=,!=,<,<=,>,>=) dstVal`
|
||||
func CompInt[T comdef.Xint](srcVal, dstVal T, op string) (ok bool) {
|
||||
return CompValue(srcVal, dstVal, op)
|
||||
// CompInt compare all intX,uintX type value. returns `first op(=,!=,<,<=,>,>=) second`
|
||||
func CompInt[T comdef.Xint](first, second T, op string) (ok bool) {
|
||||
return CompValue(first, second, op)
|
||||
}
|
||||
|
||||
// CompInt64 compare int64 value. returns `srcVal op(=,!=,<,<=,>,>=) dstVal`
|
||||
func CompInt64(srcVal, dstVal int64, op string) bool {
|
||||
return CompValue(srcVal, dstVal, op)
|
||||
// CompInt64 compare int64 value. returns `first op(=,!=,<,<=,>,>=) second`
|
||||
func CompInt64(first, second int64, op string) bool {
|
||||
return CompValue(first, second, op)
|
||||
}
|
||||
|
||||
// CompFloat compare float64,float32 value. returns `srcVal op(=,!=,<,<=,>,>=) dstVal`
|
||||
func CompFloat[T comdef.Float](srcVal, dstVal T, op string) (ok bool) {
|
||||
return CompValue(srcVal, dstVal, op)
|
||||
// CompFloat compare float64,float32 value. returns `first op(=,!=,<,<=,>,>=) second`
|
||||
func CompFloat[T comdef.Float](first, second T, op string) (ok bool) {
|
||||
return CompValue(first, second, op)
|
||||
}
|
||||
|
||||
// CompValue compare intX,uintX,floatX value. returns `srcVal op(=,!=,<,<=,>,>=) dstVal`
|
||||
func CompValue[T comdef.XintOrFloat](srcVal, dstVal T, op string) (ok bool) {
|
||||
// CompValue compare intX,uintX,floatX value. returns `first op(=,!=,<,<=,>,>=) second`
|
||||
func CompValue[T comdef.XintOrFloat](first, second T, op string) (ok bool) {
|
||||
switch op {
|
||||
case "<", "lt":
|
||||
ok = srcVal < dstVal
|
||||
ok = first < second
|
||||
case "<=", "lte":
|
||||
ok = srcVal <= dstVal
|
||||
ok = first <= second
|
||||
case ">", "gt":
|
||||
ok = srcVal > dstVal
|
||||
ok = first > second
|
||||
case ">=", "gte":
|
||||
ok = srcVal >= dstVal
|
||||
ok = first >= second
|
||||
case "=", "eq":
|
||||
ok = srcVal == dstVal
|
||||
ok = first == second
|
||||
case "!=", "ne", "neq":
|
||||
ok = srcVal != dstVal
|
||||
ok = first != second
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
76
vendor/github.com/gookit/goutil/mathutil/compare.go
generated
vendored
Normal file
76
vendor/github.com/gookit/goutil/mathutil/compare.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package mathutil
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
)
|
||||
|
||||
// Min compare two value and return max value
|
||||
func Min[T comdef.XintOrFloat](x, y T) T {
|
||||
if x < y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
// Max compare two value and return max value
|
||||
func Max[T comdef.XintOrFloat](x, y T) T {
|
||||
if x > y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
// SwapMin compare and always return [min, max] value
|
||||
func SwapMin[T comdef.XintOrFloat](x, y T) (T, T) {
|
||||
if x < y {
|
||||
return x, y
|
||||
}
|
||||
return y, x
|
||||
}
|
||||
|
||||
// SwapMax compare and always return [max, min] value
|
||||
func SwapMax[T comdef.XintOrFloat](x, y T) (T, T) {
|
||||
if x > y {
|
||||
return x, y
|
||||
}
|
||||
return y, x
|
||||
}
|
||||
|
||||
// MaxInt compare and return max value
|
||||
func MaxInt(x, y int) int {
|
||||
if x > y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
// SwapMaxInt compare and return max, min value
|
||||
func SwapMaxInt(x, y int) (int, int) {
|
||||
if x > y {
|
||||
return x, y
|
||||
}
|
||||
return y, x
|
||||
}
|
||||
|
||||
// MaxI64 compare and return max value
|
||||
func MaxI64(x, y int64) int64 {
|
||||
if x > y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
// SwapMaxI64 compare and return max, min value
|
||||
func SwapMaxI64(x, y int64) (int64, int64) {
|
||||
if x > y {
|
||||
return x, y
|
||||
}
|
||||
return y, x
|
||||
}
|
||||
|
||||
// MaxFloat compare and return max value
|
||||
func MaxFloat(x, y float64) float64 {
|
||||
return math.Max(x, y)
|
||||
}
|
||||
333
vendor/github.com/gookit/goutil/mathutil/convert.go
generated
vendored
333
vendor/github.com/gookit/goutil/mathutil/convert.go
generated
vendored
@@ -1,8 +1,8 @@
|
||||
package mathutil
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -10,6 +10,18 @@ import (
|
||||
"github.com/gookit/goutil/comdef"
|
||||
)
|
||||
|
||||
// ToIntFunc convert value to int
|
||||
type ToIntFunc func(any) (int, error)
|
||||
|
||||
// ToInt64Func convert value to int64
|
||||
type ToInt64Func func(any) (int64, error)
|
||||
|
||||
// ToUintFunc convert value to uint
|
||||
type ToUintFunc func(any) (uint64, error)
|
||||
|
||||
// ToFloatFunc convert value to float
|
||||
type ToFloatFunc func(any) (float64, error)
|
||||
|
||||
/*************************************************************
|
||||
* convert value to int
|
||||
*************************************************************/
|
||||
@@ -19,20 +31,19 @@ func Int(in any) (int, error) {
|
||||
return ToInt(in)
|
||||
}
|
||||
|
||||
// QuietInt convert value to int, will ignore error
|
||||
func QuietInt(in any) int {
|
||||
// SafeInt convert value to int, will ignore error
|
||||
func SafeInt(in any) int {
|
||||
val, _ := ToInt(in)
|
||||
return val
|
||||
}
|
||||
|
||||
// QuietInt convert value to int, will ignore error
|
||||
func QuietInt(in any) int {
|
||||
return SafeInt(in)
|
||||
}
|
||||
|
||||
// MustInt convert value to int, will panic on error
|
||||
func MustInt(in any) int {
|
||||
val, _ := ToInt(in)
|
||||
return val
|
||||
}
|
||||
|
||||
// IntOrPanic convert value to int, will panic on error
|
||||
func IntOrPanic(in any) int {
|
||||
val, err := ToInt(in)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -40,16 +51,38 @@ func IntOrPanic(in any) int {
|
||||
return val
|
||||
}
|
||||
|
||||
// IntOrPanic convert value to int, will panic on error
|
||||
func IntOrPanic(in any) int {
|
||||
return MustInt(in)
|
||||
}
|
||||
|
||||
// IntOrDefault convert value to int, return defaultVal on failed
|
||||
func IntOrDefault(in any, defVal int) int {
|
||||
return IntOr(in, defVal)
|
||||
}
|
||||
|
||||
// IntOr convert value to int, return defaultVal on failed
|
||||
func IntOr(in any, defVal int) int {
|
||||
val, err := ToIntWithFunc(in, nil)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// IntOrErr convert value to int, return error on failed
|
||||
func IntOrErr(in any) (iVal int, err error) {
|
||||
return ToInt(in)
|
||||
return ToIntWithFunc(in, nil)
|
||||
}
|
||||
|
||||
// ToInt convert value to int, return error on failed
|
||||
func ToInt(in any) (iVal int, err error) {
|
||||
return ToIntWithFunc(in, nil)
|
||||
}
|
||||
|
||||
// ToIntWithFunc convert value to int, will call usrFn on value type not supported.
|
||||
func ToIntWithFunc(in any, usrFn ToIntFunc) (iVal int, err error) {
|
||||
switch tVal := in.(type) {
|
||||
case nil:
|
||||
iVal = 0
|
||||
case int:
|
||||
iVal = tVal
|
||||
case int8:
|
||||
@@ -59,31 +92,60 @@ func ToInt(in any) (iVal int, err error) {
|
||||
case int32:
|
||||
iVal = int(tVal)
|
||||
case int64:
|
||||
iVal = int(tVal)
|
||||
if tVal > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(tVal)
|
||||
}
|
||||
case uint:
|
||||
iVal = int(tVal)
|
||||
if tVal > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(tVal)
|
||||
}
|
||||
case uint8:
|
||||
iVal = int(tVal)
|
||||
case uint16:
|
||||
iVal = int(tVal)
|
||||
case uint32:
|
||||
iVal = int(tVal)
|
||||
if tVal > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(tVal)
|
||||
}
|
||||
case uint64:
|
||||
iVal = int(tVal)
|
||||
if tVal > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(tVal)
|
||||
}
|
||||
case float32:
|
||||
iVal = int(tVal)
|
||||
case float64:
|
||||
iVal = int(tVal)
|
||||
case time.Duration:
|
||||
iVal = int(tVal)
|
||||
if tVal > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(tVal)
|
||||
}
|
||||
case string:
|
||||
iVal, err = strconv.Atoi(strings.TrimSpace(tVal))
|
||||
case json.Number:
|
||||
case interface{ Int64() (int64, error) }: // eg: json.Number
|
||||
var i64 int64
|
||||
i64, err = tVal.Int64()
|
||||
iVal = int(i64)
|
||||
if i64, err = tVal.Int64(); err == nil {
|
||||
if i64 > math.MaxInt32 {
|
||||
err = fmt.Errorf("value overflow int32. input: %v", tVal)
|
||||
} else {
|
||||
iVal = int(i64)
|
||||
}
|
||||
}
|
||||
default:
|
||||
err = comdef.ErrConvType
|
||||
if usrFn != nil {
|
||||
return usrFn(in)
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -94,37 +156,71 @@ func StrInt(s string) int {
|
||||
return iVal
|
||||
}
|
||||
|
||||
// StrIntOr convert string to int, return default val on failed
|
||||
func StrIntOr(s string, defVal int) int {
|
||||
iVal, err := strconv.Atoi(strings.TrimSpace(s))
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return iVal
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
* convert value to uint
|
||||
*************************************************************/
|
||||
|
||||
// Uint convert string to uint, return error on failed
|
||||
// Uint convert any to uint, return error on failed
|
||||
func Uint(in any) (uint64, error) {
|
||||
return ToUint(in)
|
||||
}
|
||||
|
||||
// QuietUint convert string to uint, will ignore error
|
||||
func QuietUint(in any) uint64 {
|
||||
// SafeUint convert any to uint, will ignore error
|
||||
func SafeUint(in any) uint64 {
|
||||
val, _ := ToUint(in)
|
||||
return val
|
||||
}
|
||||
|
||||
// MustUint convert string to uint, will panic on error
|
||||
// QuietUint convert any to uint, will ignore error
|
||||
func QuietUint(in any) uint64 {
|
||||
return SafeUint(in)
|
||||
}
|
||||
|
||||
// MustUint convert any to uint, will panic on error
|
||||
func MustUint(in any) uint64 {
|
||||
val, _ := ToUint(in)
|
||||
val, err := ToUintWithFunc(in, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// UintOrDefault convert any to uint, return default val on failed
|
||||
func UintOrDefault(in any, defVal uint64) uint64 {
|
||||
return UintOr(in, defVal)
|
||||
}
|
||||
|
||||
// UintOr convert any to uint, return default val on failed
|
||||
func UintOr(in any, defVal uint64) uint64 {
|
||||
val, err := ToUintWithFunc(in, nil)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// UintOrErr convert value to uint, return error on failed
|
||||
func UintOrErr(in any) (uint64, error) {
|
||||
return ToUint(in)
|
||||
return ToUintWithFunc(in, nil)
|
||||
}
|
||||
|
||||
// ToUint convert value to uint, return error on failed
|
||||
func ToUint(in any) (u64 uint64, err error) {
|
||||
return ToUintWithFunc(in, nil)
|
||||
}
|
||||
|
||||
// ToUintWithFunc convert value to uint, will call usrFn on value type not supported.
|
||||
func ToUintWithFunc(in any, usrFn ToUintFunc) (u64 uint64, err error) {
|
||||
switch tVal := in.(type) {
|
||||
case nil:
|
||||
u64 = 0
|
||||
case int:
|
||||
u64 = uint64(tVal)
|
||||
case int8:
|
||||
@@ -151,14 +247,18 @@ func ToUint(in any) (u64 uint64, err error) {
|
||||
u64 = uint64(tVal)
|
||||
case time.Duration:
|
||||
u64 = uint64(tVal)
|
||||
case json.Number:
|
||||
case interface{ Int64() (int64, error) }: // eg: json.Number
|
||||
var i64 int64
|
||||
i64, err = tVal.Int64()
|
||||
u64 = uint64(i64)
|
||||
case string:
|
||||
u64, err = strconv.ParseUint(strings.TrimSpace(tVal), 10, 0)
|
||||
default:
|
||||
err = comdef.ErrConvType
|
||||
if usrFn != nil {
|
||||
u64, err = usrFn(in)
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -167,41 +267,58 @@ func ToUint(in any) (u64 uint64, err error) {
|
||||
* convert value to int64
|
||||
*************************************************************/
|
||||
|
||||
// Int64 convert string to int64, return error on failed
|
||||
// Int64 convert value to int64, return error on failed
|
||||
func Int64(in any) (int64, error) {
|
||||
return ToInt64(in)
|
||||
}
|
||||
|
||||
// SafeInt64 convert value to int64, will ignore error
|
||||
func SafeInt64(in any) int64 {
|
||||
i64, _ := ToInt64(in)
|
||||
i64, _ := ToInt64WithFunc(in, nil)
|
||||
return i64
|
||||
}
|
||||
|
||||
// QuietInt64 convert value to int64, will ignore error
|
||||
func QuietInt64(in any) int64 {
|
||||
i64, _ := ToInt64(in)
|
||||
return i64
|
||||
return SafeInt64(in)
|
||||
}
|
||||
|
||||
// MustInt64 convert value to int64, will panic on error
|
||||
func MustInt64(in any) int64 {
|
||||
i64, _ := ToInt64(in)
|
||||
i64, err := ToInt64WithFunc(in, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return i64
|
||||
}
|
||||
|
||||
// TODO StrictInt64,AsInt64 strict convert to int64
|
||||
// Int64OrDefault convert value to int64, return default val on failed
|
||||
func Int64OrDefault(in any, defVal int64) int64 {
|
||||
return Int64Or(in, defVal)
|
||||
}
|
||||
|
||||
// Int64OrErr convert string to int64, return error on failed
|
||||
// Int64Or convert value to int64, return default val on failed
|
||||
func Int64Or(in any, defVal int64) int64 {
|
||||
i64, err := ToInt64WithFunc(in, nil)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return i64
|
||||
}
|
||||
|
||||
// Int64OrErr convert value to int64, return error on failed
|
||||
func Int64OrErr(in any) (int64, error) {
|
||||
return ToInt64(in)
|
||||
}
|
||||
|
||||
// ToInt64 convert string to int64, return error on failed
|
||||
// ToInt64 convert value to int64, return error on failed
|
||||
func ToInt64(in any) (i64 int64, err error) {
|
||||
return ToInt64WithFunc(in, nil)
|
||||
}
|
||||
|
||||
// ToInt64WithFunc convert value to int64, will call usrFn on value type not supported.
|
||||
func ToInt64WithFunc(in any, usrFn ToInt64Func) (i64 int64, err error) {
|
||||
switch tVal := in.(type) {
|
||||
case nil:
|
||||
i64 = 0
|
||||
case string:
|
||||
i64, err = strconv.ParseInt(strings.TrimSpace(tVal), 10, 0)
|
||||
case int:
|
||||
@@ -230,10 +347,14 @@ func ToInt64(in any) (i64 int64, err error) {
|
||||
i64 = int64(tVal)
|
||||
case time.Duration:
|
||||
i64 = int64(tVal)
|
||||
case json.Number:
|
||||
case interface{ Int64() (int64, error) }: // eg: json.Number
|
||||
i64, err = tVal.Int64()
|
||||
default:
|
||||
err = comdef.ErrConvType
|
||||
if usrFn != nil {
|
||||
i64, err = usrFn(in)
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -242,42 +363,63 @@ func ToInt64(in any) (i64 int64, err error) {
|
||||
* convert value to float
|
||||
*************************************************************/
|
||||
|
||||
// QuietFloat convert value to float64, will ignore error
|
||||
// QuietFloat convert value to float64, will ignore error. alias of SafeFloat
|
||||
func QuietFloat(in any) float64 {
|
||||
val, _ := ToFloat(in)
|
||||
return SafeFloat(in)
|
||||
}
|
||||
|
||||
// SafeFloat convert value to float64, will ignore error
|
||||
func SafeFloat(in any) float64 {
|
||||
val, _ := ToFloatWithFunc(in, nil)
|
||||
return val
|
||||
}
|
||||
|
||||
// FloatOrPanic convert value to float64, will panic on error
|
||||
func FloatOrPanic(in any) float64 {
|
||||
val, err := ToFloat(in)
|
||||
return MustFloat(in)
|
||||
}
|
||||
|
||||
// MustFloat convert value to float64, will panic on error
|
||||
func MustFloat(in any) float64 {
|
||||
val, err := ToFloatWithFunc(in, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// MustFloat convert value to float64 TODO will panic on error
|
||||
func MustFloat(in any) float64 {
|
||||
val, _ := ToFloat(in)
|
||||
// FloatOrDefault convert value to float64, will return default value on error
|
||||
func FloatOrDefault(in any, defVal float64) float64 {
|
||||
return FloatOr(in, defVal)
|
||||
}
|
||||
|
||||
// FloatOr convert value to float64, will return default value on error
|
||||
func FloatOr(in any, defVal float64) float64 {
|
||||
val, err := ToFloatWithFunc(in, nil)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Float convert value to float64, return error on failed
|
||||
func Float(in any) (float64, error) {
|
||||
return ToFloat(in)
|
||||
return ToFloatWithFunc(in, nil)
|
||||
}
|
||||
|
||||
// FloatOrErr convert value to float64, return error on failed
|
||||
func FloatOrErr(in any) (float64, error) {
|
||||
return ToFloat(in)
|
||||
return ToFloatWithFunc(in, nil)
|
||||
}
|
||||
|
||||
// ToFloat convert value to float64, return error on failed
|
||||
func ToFloat(in any) (f64 float64, err error) {
|
||||
return ToFloatWithFunc(in, nil)
|
||||
}
|
||||
|
||||
// ToFloatWithFunc convert value to float64, will call usrFn if value type not supported.
|
||||
func ToFloatWithFunc(in any, usrFn ToFloatFunc) (f64 float64, err error) {
|
||||
switch tVal := in.(type) {
|
||||
case nil:
|
||||
f64 = 0
|
||||
case string:
|
||||
f64, err = strconv.ParseFloat(strings.TrimSpace(tVal), 64)
|
||||
case int:
|
||||
@@ -306,10 +448,14 @@ func ToFloat(in any) (f64 float64, err error) {
|
||||
f64 = tVal
|
||||
case time.Duration:
|
||||
f64 = float64(tVal)
|
||||
case json.Number:
|
||||
case interface{ Float64() (float64, error) }: // eg: json.Number
|
||||
f64, err = tVal.Float64()
|
||||
default:
|
||||
err = comdef.ErrConvType
|
||||
if usrFn != nil {
|
||||
f64, err = usrFn(in)
|
||||
} else {
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -318,34 +464,45 @@ func ToFloat(in any) (f64 float64, err error) {
|
||||
* convert intX/floatX to string
|
||||
*************************************************************/
|
||||
|
||||
// StringOrPanic convert intX/floatX value to string, will panic on error
|
||||
func StringOrPanic(val any) string {
|
||||
str, err := TryToString(val, true)
|
||||
// MustString convert intX/floatX value to string, will panic on error
|
||||
func MustString(val any) string {
|
||||
str, err := ToStringWithFunc(val, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// MustString convert intX/floatX value to string, will panic on error
|
||||
func MustString(val any) string {
|
||||
return StringOrPanic(val)
|
||||
// StringOrPanic convert intX/floatX value to string, will panic on error
|
||||
func StringOrPanic(val any) string { return MustString(val) }
|
||||
|
||||
// StringOrDefault convert intX/floatX value to string, will return default value on error
|
||||
func StringOrDefault(val any, defVal string) string {
|
||||
return StringOr(val, defVal)
|
||||
}
|
||||
|
||||
// StringOr convert intX/floatX value to string, will return default value on error
|
||||
func StringOr(val any, defVal string) string {
|
||||
str, err := ToStringWithFunc(val, nil)
|
||||
if err != nil {
|
||||
return defVal
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// ToString convert intX/floatX value to string, return error on failed
|
||||
func ToString(val any) (string, error) {
|
||||
return TryToString(val, true)
|
||||
return ToStringWithFunc(val, nil)
|
||||
}
|
||||
|
||||
// StringOrErr convert intX/floatX value to string, return error on failed
|
||||
func StringOrErr(val any) (string, error) {
|
||||
return TryToString(val, true)
|
||||
return ToStringWithFunc(val, nil)
|
||||
}
|
||||
|
||||
// QuietString convert intX/floatX value to string, other type convert by fmt.Sprint
|
||||
func QuietString(val any) string {
|
||||
str, _ := TryToString(val, false)
|
||||
return str
|
||||
return SafeString(val)
|
||||
}
|
||||
|
||||
// String convert intX/floatX value to string, other type convert by fmt.Sprint
|
||||
@@ -354,14 +511,33 @@ func String(val any) string {
|
||||
return str
|
||||
}
|
||||
|
||||
// SafeString convert intX/floatX value to string, other type convert by fmt.Sprint
|
||||
func SafeString(val any) string {
|
||||
str, _ := TryToString(val, false)
|
||||
return str
|
||||
}
|
||||
|
||||
// TryToString try convert intX/floatX value to string
|
||||
//
|
||||
// if defaultAsErr is False, will use fmt.Sprint convert other type
|
||||
func TryToString(val any, defaultAsErr bool) (str string, err error) {
|
||||
if val == nil {
|
||||
return
|
||||
var usrFn comdef.ToStringFunc
|
||||
if !defaultAsErr {
|
||||
usrFn = func(v any) (string, error) {
|
||||
if val == nil {
|
||||
return "", nil
|
||||
}
|
||||
return fmt.Sprint(v), nil
|
||||
}
|
||||
}
|
||||
|
||||
return ToStringWithFunc(val, usrFn)
|
||||
}
|
||||
|
||||
// ToStringWithFunc try convert intX/floatX value to string, will call usrFn if value type not supported.
|
||||
//
|
||||
// if defaultAsErr is False, will use fmt.Sprint convert other type
|
||||
func ToStringWithFunc(val any, usrFn comdef.ToStringFunc) (str string, err error) {
|
||||
switch value := val.(type) {
|
||||
case int:
|
||||
str = strconv.Itoa(value)
|
||||
@@ -389,14 +565,31 @@ func TryToString(val any, defaultAsErr bool) (str string, err error) {
|
||||
str = strconv.FormatFloat(value, 'f', -1, 64)
|
||||
case time.Duration:
|
||||
str = strconv.FormatInt(int64(value), 10)
|
||||
case string:
|
||||
str = value
|
||||
case fmt.Stringer:
|
||||
str = value.String()
|
||||
default:
|
||||
if defaultAsErr {
|
||||
err = comdef.ErrConvType
|
||||
if usrFn != nil {
|
||||
str, err = usrFn(val)
|
||||
} else {
|
||||
str = fmt.Sprint(value)
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Percent returns a values percent of the total
|
||||
func Percent(val, total int) float64 {
|
||||
if total == 0 {
|
||||
return float64(0)
|
||||
}
|
||||
return (float64(val) / float64(total)) * 100
|
||||
}
|
||||
|
||||
// ElapsedTime calc elapsed time 计算运行时间消耗 单位 ms(毫秒)
|
||||
//
|
||||
// Deprecated: use timex.ElapsedTime()
|
||||
func ElapsedTime(startTime time.Time) string {
|
||||
return fmt.Sprintf("%.3f", time.Since(startTime).Seconds()*1000)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package basefn
|
||||
package mathutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
import "fmt"
|
||||
|
||||
// DataSize format bytes number friendly. eg: 1024 => 1KB, 1024*1024 => 1MB
|
||||
//
|
||||
@@ -33,14 +31,16 @@ var timeFormats = [][]int{
|
||||
{3600},
|
||||
{7200, 3600},
|
||||
{86400},
|
||||
{172800, 86400},
|
||||
{172800, 86400}, // second elem is unit.
|
||||
{2592000},
|
||||
{2592000 * 2, 2592000},
|
||||
}
|
||||
|
||||
var timeMessages = []string{
|
||||
"< 1 sec", "1 sec", "secs", "1 min", "mins", "1 hr", "hrs", "1 day", "days",
|
||||
"< 1 sec", "1 sec", "secs", "1 min", "mins", "1 hr", "hrs", "1 day", "days", "1 month", "months",
|
||||
}
|
||||
|
||||
// HowLongAgo format a seconds, get how lang ago
|
||||
// HowLongAgo format a seconds, get how lang ago. eg: 1 day, 1 week
|
||||
func HowLongAgo(sec int64) string {
|
||||
intVal := int(sec)
|
||||
length := len(timeFormats)
|
||||
@@ -63,8 +63,6 @@ func HowLongAgo(sec int64) string {
|
||||
if len(item) == 1 {
|
||||
return timeMessages[i]
|
||||
}
|
||||
|
||||
// len is 2
|
||||
return fmt.Sprintf("%d %s", intVal/item[1], timeMessages[i])
|
||||
}
|
||||
}
|
||||
112
vendor/github.com/gookit/goutil/mathutil/mathutil.go
generated
vendored
112
vendor/github.com/gookit/goutil/mathutil/mathutil.go
generated
vendored
@@ -2,84 +2,72 @@
|
||||
package mathutil
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/gookit/goutil/comdef"
|
||||
)
|
||||
|
||||
// Min compare two value and return max value
|
||||
func Min[T comdef.XintOrFloat](x, y T) T {
|
||||
if x < y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
// OrElse return default value on val is zero, else return val
|
||||
func OrElse[T comdef.XintOrFloat](val, defVal T) T {
|
||||
return ZeroOr(val, defVal)
|
||||
}
|
||||
|
||||
// Max compare two value and return max value
|
||||
func Max[T comdef.XintOrFloat](x, y T) T {
|
||||
if x > y {
|
||||
return x
|
||||
// ZeroOr return default value on val is zero, else return val
|
||||
func ZeroOr[T comdef.XintOrFloat](val, defVal T) T {
|
||||
if val != 0 {
|
||||
return val
|
||||
}
|
||||
return y
|
||||
return defVal
|
||||
}
|
||||
|
||||
// SwapMin compare and always return [min, max] value
|
||||
func SwapMin[T comdef.XintOrFloat](x, y T) (T, T) {
|
||||
if x < y {
|
||||
return x, y
|
||||
// LessOr return val on val < max, else return default value.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// LessOr(11, 10, 1) // 1
|
||||
// LessOr(2, 10, 1) // 2
|
||||
// LessOr(10, 10, 1) // 1
|
||||
func LessOr[T comdef.XintOrFloat](val, max, devVal T) T {
|
||||
if val < max {
|
||||
return val
|
||||
}
|
||||
return y, x
|
||||
return devVal
|
||||
}
|
||||
|
||||
// SwapMax compare and always return [max, min] value
|
||||
func SwapMax[T comdef.XintOrFloat](x, y T) (T, T) {
|
||||
if x > y {
|
||||
return x, y
|
||||
// LteOr return val on val <= max, else return default value.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// LteOr(11, 10, 1) // 11
|
||||
// LteOr(2, 10, 1) // 2
|
||||
// LteOr(10, 10, 1) // 10
|
||||
func LteOr[T comdef.XintOrFloat](val, max, devVal T) T {
|
||||
if val <= max {
|
||||
return val
|
||||
}
|
||||
return y, x
|
||||
return devVal
|
||||
}
|
||||
|
||||
// MaxInt compare and return max value
|
||||
func MaxInt(x, y int) int {
|
||||
if x > y {
|
||||
return x
|
||||
// GreaterOr return val on val > max, else return default value.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// GreaterOr(23, 0, 2) // 23
|
||||
// GreaterOr(0, 0, 2) // 2
|
||||
func GreaterOr[T comdef.XintOrFloat](val, min, defVal T) T {
|
||||
if val > min {
|
||||
return val
|
||||
}
|
||||
return y
|
||||
return defVal
|
||||
}
|
||||
|
||||
// SwapMaxInt compare and return max, min value
|
||||
func SwapMaxInt(x, y int) (int, int) {
|
||||
if x > y {
|
||||
return x, y
|
||||
// GteOr return val on val >= max, else return default value.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// GteOr(23, 0, 2) // 23
|
||||
// GteOr(0, 0, 2) // 0
|
||||
func GteOr[T comdef.XintOrFloat](val, min, defVal T) T {
|
||||
if val >= min {
|
||||
return val
|
||||
}
|
||||
return y, x
|
||||
}
|
||||
|
||||
// MaxI64 compare and return max value
|
||||
func MaxI64(x, y int64) int64 {
|
||||
if x > y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
// SwapMaxI64 compare and return max, min value
|
||||
func SwapMaxI64(x, y int64) (int64, int64) {
|
||||
if x > y {
|
||||
return x, y
|
||||
}
|
||||
return y, x
|
||||
}
|
||||
|
||||
// MaxFloat compare and return max value
|
||||
func MaxFloat(x, y float64) float64 {
|
||||
return math.Max(x, y)
|
||||
}
|
||||
|
||||
// OrElse return s OR nv(new-value) on s is empty
|
||||
func OrElse[T comdef.XintOrFloat](in, nv T) T {
|
||||
if in != 0 {
|
||||
return in
|
||||
}
|
||||
return nv
|
||||
return defVal
|
||||
}
|
||||
|
||||
37
vendor/github.com/gookit/goutil/mathutil/number.go
generated
vendored
37
vendor/github.com/gookit/goutil/mathutil/number.go
generated
vendored
@@ -1,37 +0,0 @@
|
||||
package mathutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gookit/goutil/basefn"
|
||||
)
|
||||
|
||||
// IsNumeric returns true if the given character is a numeric, otherwise false.
|
||||
func IsNumeric(c byte) bool {
|
||||
return c >= '0' && c <= '9'
|
||||
}
|
||||
|
||||
// Percent returns a values percent of the total
|
||||
func Percent(val, total int) float64 {
|
||||
if total == 0 {
|
||||
return float64(0)
|
||||
}
|
||||
return (float64(val) / float64(total)) * 100
|
||||
}
|
||||
|
||||
// ElapsedTime calc elapsed time 计算运行时间消耗 单位 ms(毫秒)
|
||||
func ElapsedTime(startTime time.Time) string {
|
||||
return fmt.Sprintf("%.3f", time.Since(startTime).Seconds()*1000)
|
||||
}
|
||||
|
||||
// DataSize format value to data size string. eg: 1024 => 1KB, 1024*1024 => 1MB
|
||||
// alias format.DataSize()
|
||||
func DataSize(size uint64) string {
|
||||
return basefn.DataSize(size)
|
||||
}
|
||||
|
||||
// HowLongAgo calc time. alias format.HowLongAgo()
|
||||
func HowLongAgo(sec int64) string {
|
||||
return basefn.HowLongAgo(sec)
|
||||
}
|
||||
8
vendor/github.com/gookit/goutil/mathutil/random.go
generated
vendored
8
vendor/github.com/gookit/goutil/mathutil/random.go
generated
vendored
@@ -13,8 +13,8 @@ import (
|
||||
// RandomInt(100, 999)
|
||||
// RandomInt(1000, 9999)
|
||||
func RandomInt(min, max int) int {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
return min + rand.Intn(max-min)
|
||||
rr := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
return min + rr.Intn(max-min)
|
||||
}
|
||||
|
||||
// RandInt alias of RandomInt()
|
||||
@@ -32,6 +32,6 @@ func RandIntWithSeed(min, max int, seed int64) int {
|
||||
// seed := time.Now().UnixNano()
|
||||
// RandomIntWithSeed(1000, 9999, seed)
|
||||
func RandomIntWithSeed(min, max int, seed int64) int {
|
||||
rand.Seed(seed)
|
||||
return min + rand.Intn(max-min)
|
||||
rr := rand.New(rand.NewSource(seed))
|
||||
return min + rr.Intn(max-min)
|
||||
}
|
||||
|
||||
38
vendor/github.com/gookit/goutil/reflects/check.go
generated
vendored
38
vendor/github.com/gookit/goutil/reflects/check.go
generated
vendored
@@ -27,11 +27,16 @@ func IsSimpleKind(k reflect.Kind) bool {
|
||||
return k > reflect.Invalid && k <= reflect.Float64
|
||||
}
|
||||
|
||||
// IsAnyInt check is intX or uintX type
|
||||
// IsAnyInt check is intX or uintX type. alias of the IsIntLike()
|
||||
func IsAnyInt(k reflect.Kind) bool {
|
||||
return k >= reflect.Int && k <= reflect.Uintptr
|
||||
}
|
||||
|
||||
// IsIntLike reports whether the type is int-like(intX, uintX).
|
||||
func IsIntLike(k reflect.Kind) bool {
|
||||
return k >= reflect.Int && k <= reflect.Uintptr
|
||||
}
|
||||
|
||||
// IsIntx check is intX type
|
||||
func IsIntx(k reflect.Kind) bool {
|
||||
return k >= reflect.Int && k <= reflect.Int64
|
||||
@@ -52,6 +57,17 @@ func IsNil(v reflect.Value) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// CanBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero.
|
||||
func CanBeNil(typ reflect.Type) bool {
|
||||
switch typ.Kind() {
|
||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice:
|
||||
return true
|
||||
case reflect.Struct:
|
||||
return typ == reflectValueType
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsFunc value
|
||||
func IsFunc(val any) bool {
|
||||
if val == nil {
|
||||
@@ -84,6 +100,9 @@ func IsEqual(src, dst any) bool {
|
||||
return bytes.Equal(bs1, bs2)
|
||||
}
|
||||
|
||||
// IsZero reflect value check, alias of the IsEmpty()
|
||||
var IsZero = IsEmpty
|
||||
|
||||
// IsEmpty reflect value check
|
||||
func IsEmpty(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
@@ -108,11 +127,17 @@ func IsEmpty(v reflect.Value) bool {
|
||||
return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
|
||||
}
|
||||
|
||||
// IsEmptyValue reflect value check.
|
||||
// Difference the IsEmpty(), if value is ptr, will check real elem.
|
||||
// IsEmptyValue reflect value check, alias of the IsEmptyReal()
|
||||
var IsEmptyValue = IsEmptyReal
|
||||
|
||||
// IsEmptyReal reflect value check.
|
||||
//
|
||||
// Note:
|
||||
//
|
||||
// Difference the IsEmpty(), if value is ptr or interface, will check real elem.
|
||||
//
|
||||
// From src/pkg/encoding/json/encode.go.
|
||||
func IsEmptyValue(v reflect.Value) bool {
|
||||
func IsEmptyReal(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||
return v.Len() == 0
|
||||
@@ -128,11 +153,12 @@ func IsEmptyValue(v reflect.Value) bool {
|
||||
if v.IsNil() {
|
||||
return true
|
||||
}
|
||||
return IsEmptyValue(v.Elem())
|
||||
return IsEmptyReal(v.Elem())
|
||||
case reflect.Func:
|
||||
return v.IsNil()
|
||||
case reflect.Invalid:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
|
||||
}
|
||||
|
||||
106
vendor/github.com/gookit/goutil/reflects/conv.go
generated
vendored
106
vendor/github.com/gookit/goutil/reflects/conv.go
generated
vendored
@@ -2,6 +2,7 @@ package reflects
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
@@ -12,13 +13,19 @@ import (
|
||||
)
|
||||
|
||||
// BaseTypeVal convert custom type or intX,uintX,floatX to generic base type.
|
||||
func BaseTypeVal(v reflect.Value) (value any, err error) {
|
||||
return ToBaseVal(v)
|
||||
}
|
||||
|
||||
// ToBaseVal convert custom type or intX,uintX,floatX to generic base type.
|
||||
//
|
||||
// intX/unitX => int64
|
||||
// intX => int64
|
||||
// unitX => uint64
|
||||
// floatX => float64
|
||||
// string => string
|
||||
//
|
||||
// returns int64,string,float or error
|
||||
func BaseTypeVal(v reflect.Value) (value any, err error) {
|
||||
func ToBaseVal(v reflect.Value) (value any, err error) {
|
||||
v = reflect.Indirect(v)
|
||||
|
||||
switch v.Kind() {
|
||||
@@ -27,7 +34,7 @@ func BaseTypeVal(v reflect.Value) (value any, err error) {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
value = v.Int()
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
value = int64(v.Uint()) // always return int64
|
||||
value = v.Uint() // always return int64
|
||||
case reflect.Float32, reflect.Float64:
|
||||
value = v.Float()
|
||||
default:
|
||||
@@ -36,14 +43,23 @@ func BaseTypeVal(v reflect.Value) (value any, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// ConvToType convert and create reflect.Value by give reflect.Type
|
||||
func ConvToType(val any, typ reflect.Type) (rv reflect.Value, err error) {
|
||||
return ValueByType(val, typ)
|
||||
}
|
||||
|
||||
// ValueByType create reflect.Value by give reflect.Type
|
||||
func ValueByType(val any, typ reflect.Type) (rv reflect.Value, err error) {
|
||||
// handle kind: string, bool, intX, uintX, floatX
|
||||
if typ.Kind() == reflect.String || typ.Kind() <= reflect.Float64 {
|
||||
return ValueByKind(val, typ.Kind())
|
||||
return ConvToKind(val, typ.Kind())
|
||||
}
|
||||
|
||||
newRv := reflect.ValueOf(val)
|
||||
var ok bool
|
||||
var newRv reflect.Value
|
||||
if newRv, ok = val.(reflect.Value); !ok {
|
||||
newRv = reflect.ValueOf(val)
|
||||
}
|
||||
|
||||
// try auto convert slice type
|
||||
if IsArrayOrSlice(newRv.Kind()) && IsArrayOrSlice(typ.Kind()) {
|
||||
@@ -59,72 +75,116 @@ func ValueByType(val any, typ reflect.Type) (rv reflect.Value, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// ValueByKind create reflect.Value by give reflect.Kind
|
||||
// ValueByKind convert and create reflect.Value by give reflect.Kind
|
||||
func ValueByKind(val any, kind reflect.Kind) (rv reflect.Value, err error) {
|
||||
return ConvToKind(val, kind)
|
||||
}
|
||||
|
||||
// ConvToKind convert and create reflect.Value by give reflect.Kind
|
||||
//
|
||||
// TIPs:
|
||||
//
|
||||
// Only support kind: string, bool, intX, uintX, floatX
|
||||
func ValueByKind(val any, kind reflect.Kind) (rv reflect.Value, err error) {
|
||||
func ConvToKind(val any, kind reflect.Kind) (rv reflect.Value, err error) {
|
||||
if rv, ok := val.(reflect.Value); ok {
|
||||
val = rv.Interface()
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case reflect.Int:
|
||||
if dstV, err1 := mathutil.ToInt(val); err1 == nil {
|
||||
var dstV int
|
||||
if dstV, err = mathutil.ToInt(val); err == nil {
|
||||
rv = reflect.ValueOf(dstV)
|
||||
}
|
||||
case reflect.Int8:
|
||||
if dstV, err1 := mathutil.ToInt(val); err1 == nil {
|
||||
var dstV int
|
||||
if dstV, err = mathutil.ToInt(val); err == nil {
|
||||
if dstV > math.MaxInt8 {
|
||||
return rv, fmt.Errorf("value overflow int8. val: %v", val)
|
||||
}
|
||||
rv = reflect.ValueOf(int8(dstV))
|
||||
}
|
||||
case reflect.Int16:
|
||||
if dstV, err1 := mathutil.ToInt(val); err1 == nil {
|
||||
var dstV int
|
||||
if dstV, err = mathutil.ToInt(val); err == nil {
|
||||
if dstV > math.MaxInt16 {
|
||||
return rv, fmt.Errorf("value overflow int16. val: %v", val)
|
||||
}
|
||||
rv = reflect.ValueOf(int16(dstV))
|
||||
}
|
||||
case reflect.Int32:
|
||||
if dstV, err1 := mathutil.ToInt(val); err1 == nil {
|
||||
var dstV int
|
||||
if dstV, err = mathutil.ToInt(val); err == nil {
|
||||
if dstV > math.MaxInt32 {
|
||||
return rv, fmt.Errorf("value overflow int32. val: %v", val)
|
||||
}
|
||||
rv = reflect.ValueOf(int32(dstV))
|
||||
}
|
||||
case reflect.Int64:
|
||||
if dstV, err1 := mathutil.ToInt64(val); err1 == nil {
|
||||
var dstV int64
|
||||
if dstV, err = mathutil.ToInt64(val); err == nil {
|
||||
rv = reflect.ValueOf(dstV)
|
||||
}
|
||||
case reflect.Uint:
|
||||
if dstV, err1 := mathutil.ToUint(val); err1 == nil {
|
||||
var dstV uint64
|
||||
if dstV, err = mathutil.ToUint(val); err == nil {
|
||||
rv = reflect.ValueOf(uint(dstV))
|
||||
}
|
||||
case reflect.Uint8:
|
||||
if dstV, err1 := mathutil.ToUint(val); err1 == nil {
|
||||
var dstV uint64
|
||||
if dstV, err = mathutil.ToUint(val); err == nil {
|
||||
if dstV > math.MaxUint8 {
|
||||
return rv, fmt.Errorf("value overflow uint8. val: %v", val)
|
||||
}
|
||||
rv = reflect.ValueOf(uint8(dstV))
|
||||
}
|
||||
case reflect.Uint16:
|
||||
if dstV, err1 := mathutil.ToUint(val); err1 == nil {
|
||||
var dstV uint64
|
||||
if dstV, err = mathutil.ToUint(val); err == nil {
|
||||
if dstV > math.MaxUint16 {
|
||||
return rv, fmt.Errorf("value overflow uint16. val: %v", val)
|
||||
}
|
||||
rv = reflect.ValueOf(uint16(dstV))
|
||||
}
|
||||
case reflect.Uint32:
|
||||
if dstV, err1 := mathutil.ToUint(val); err1 == nil {
|
||||
var dstV uint64
|
||||
if dstV, err = mathutil.ToUint(val); err == nil {
|
||||
if dstV > math.MaxUint32 {
|
||||
return rv, fmt.Errorf("value overflow uint32. val: %v", val)
|
||||
}
|
||||
rv = reflect.ValueOf(uint32(dstV))
|
||||
}
|
||||
case reflect.Uint64:
|
||||
if dstV, err1 := mathutil.ToUint(val); err1 == nil {
|
||||
var dstV uint64
|
||||
if dstV, err = mathutil.ToUint(val); err == nil {
|
||||
rv = reflect.ValueOf(dstV)
|
||||
}
|
||||
case reflect.Float32:
|
||||
if dstV, err1 := mathutil.ToFloat(val); err1 == nil {
|
||||
var dstV float64
|
||||
if dstV, err = mathutil.ToFloat(val); err == nil {
|
||||
if dstV > math.MaxFloat32 {
|
||||
return rv, fmt.Errorf("value overflow float32. val: %v", val)
|
||||
}
|
||||
rv = reflect.ValueOf(float32(dstV))
|
||||
}
|
||||
case reflect.Float64:
|
||||
if dstV, err1 := mathutil.ToFloat(val); err1 == nil {
|
||||
var dstV float64
|
||||
if dstV, err = mathutil.ToFloat(val); err == nil {
|
||||
rv = reflect.ValueOf(dstV)
|
||||
}
|
||||
case reflect.String:
|
||||
if dstV, err1 := strutil.ToString(val); err1 == nil {
|
||||
rv = reflect.ValueOf(dstV)
|
||||
} else {
|
||||
err = err1
|
||||
}
|
||||
case reflect.Bool:
|
||||
if bl, err := comfunc.ToBool(val); err == nil {
|
||||
if bl, err1 := comfunc.ToBool(val); err1 == nil {
|
||||
rv = reflect.ValueOf(bl)
|
||||
} else {
|
||||
err = err1
|
||||
}
|
||||
}
|
||||
|
||||
if !rv.IsValid() {
|
||||
default:
|
||||
err = comdef.ErrConvType
|
||||
}
|
||||
return
|
||||
|
||||
317
vendor/github.com/gookit/goutil/reflects/func.go
generated
vendored
Normal file
317
vendor/github.com/gookit/goutil/reflects/func.go
generated
vendored
Normal file
@@ -0,0 +1,317 @@
|
||||
package reflects
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/gookit/goutil/basefn"
|
||||
)
|
||||
|
||||
// FuncX wrap a go func. represent a function
|
||||
type FuncX struct {
|
||||
CallOpt
|
||||
// Name of func. eg: "MyFunc"
|
||||
Name string
|
||||
// rv is the `reflect.Value` of func
|
||||
rv reflect.Value
|
||||
rt reflect.Type
|
||||
}
|
||||
|
||||
// NewFunc instance. param fn support func and reflect.Value
|
||||
func NewFunc(fn any) *FuncX {
|
||||
var ok bool
|
||||
var rv reflect.Value
|
||||
if rv, ok = fn.(reflect.Value); !ok {
|
||||
rv = reflect.ValueOf(fn)
|
||||
}
|
||||
|
||||
rv = indirectInterface(rv)
|
||||
if !rv.IsValid() {
|
||||
panic("input func is nil")
|
||||
}
|
||||
|
||||
typ := rv.Type()
|
||||
if typ.Kind() != reflect.Func {
|
||||
basefn.Panicf("non-function of type: %s", typ)
|
||||
}
|
||||
|
||||
return &FuncX{rv: rv, rt: typ}
|
||||
}
|
||||
|
||||
// NumIn get the number of func input args
|
||||
func (f *FuncX) NumIn() int {
|
||||
return f.rt.NumIn()
|
||||
}
|
||||
|
||||
// NumOut get the number of func output args
|
||||
func (f *FuncX) NumOut() int {
|
||||
return f.rt.NumOut()
|
||||
}
|
||||
|
||||
// Call the function with given arguments.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// func main() {
|
||||
// fn := func(a, b int) int {
|
||||
// return a + b
|
||||
// }
|
||||
//
|
||||
// fx := NewFunc(fn)
|
||||
// ret, err := fx.Call(1, 2)
|
||||
// fmt.Println(ret[0], err) // Output: 3 <nil>
|
||||
// }
|
||||
func (f *FuncX) Call(args ...any) ([]any, error) {
|
||||
// convert args to []reflect.Value
|
||||
argRvs := make([]reflect.Value, len(args))
|
||||
for i, arg := range args {
|
||||
argRvs[i] = reflect.ValueOf(arg)
|
||||
}
|
||||
|
||||
ret, err := f.CallRV(argRvs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// convert ret to []any
|
||||
rets := make([]any, len(ret))
|
||||
for i, r := range ret {
|
||||
rets[i] = r.Interface()
|
||||
}
|
||||
return rets, nil
|
||||
}
|
||||
|
||||
// Call2 returns the result of evaluating the first argument as a function.
|
||||
// The function must return 1 result, or 2 results, the second of which is an error.
|
||||
//
|
||||
// - Only support func with 1 or 2 return values: (val) OR (val, err)
|
||||
// - Will check args and try convert input args to func args type.
|
||||
func (f *FuncX) Call2(args ...any) (any, error) {
|
||||
// convert args to []reflect.Value
|
||||
argRvs := make([]reflect.Value, len(args))
|
||||
for i, arg := range args {
|
||||
argRvs[i] = reflect.ValueOf(arg)
|
||||
}
|
||||
|
||||
if f.TypeChecker == nil {
|
||||
f.TypeChecker = OneOrTwoOutChecker
|
||||
}
|
||||
|
||||
// do call func
|
||||
ret, err := Call(f.rv, argRvs, &f.CallOpt)
|
||||
if err != nil {
|
||||
return emptyValue, err
|
||||
}
|
||||
|
||||
// func return like: (val, err)
|
||||
if len(ret) == 2 && !ret[1].IsNil() {
|
||||
return ret[0].Interface(), ret[1].Interface().(error)
|
||||
}
|
||||
return ret[0].Interface(), nil
|
||||
}
|
||||
|
||||
// CallRV call the function with given reflect.Value arguments.
|
||||
func (f *FuncX) CallRV(args []reflect.Value) ([]reflect.Value, error) {
|
||||
return Call(f.rv, args, &f.CallOpt)
|
||||
}
|
||||
|
||||
// WithTypeChecker set type checker
|
||||
func (f *FuncX) WithTypeChecker(checker TypeCheckerFn) *FuncX {
|
||||
f.TypeChecker = checker
|
||||
return f
|
||||
}
|
||||
|
||||
// WithEnhanceConv set enhance convert
|
||||
func (f *FuncX) WithEnhanceConv() *FuncX {
|
||||
f.EnhanceConv = true
|
||||
return f
|
||||
}
|
||||
|
||||
// String of func
|
||||
func (f *FuncX) String() string {
|
||||
return f.rt.String()
|
||||
}
|
||||
|
||||
// TypeCheckerFn type checker func
|
||||
type TypeCheckerFn func(typ reflect.Type) error
|
||||
|
||||
// CallOpt call options
|
||||
type CallOpt struct {
|
||||
// TypeChecker check func type before call func. eg: check return values
|
||||
TypeChecker TypeCheckerFn
|
||||
// EnhanceConv try to enhance auto convert args to func args type
|
||||
// - support more type: string, int, uint, float, bool
|
||||
EnhanceConv bool
|
||||
}
|
||||
|
||||
// OneOrTwoOutChecker check func type. only allow 1 or 2 return values
|
||||
//
|
||||
// Allow func returns:
|
||||
// - 1 return: (value)
|
||||
// - 2 return: (value, error)
|
||||
var OneOrTwoOutChecker = func(typ reflect.Type) error {
|
||||
if !good1or2outFunc(typ) {
|
||||
return errors.New("func allow with 1 result or 2 results where the second is an error")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//
|
||||
// TIP:
|
||||
// flow func refer from text/template package.
|
||||
//
|
||||
//
|
||||
|
||||
// reports whether the function or method has the right result signature.
|
||||
func good1or2outFunc(typ reflect.Type) bool {
|
||||
// We allow functions with 1 result or 2 results where the second is an error.
|
||||
switch {
|
||||
case typ.NumOut() == 1:
|
||||
return true
|
||||
case typ.NumOut() == 2 && typ.Out(1) == errorType:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Call2 returns the result of evaluating the first argument as a function.
|
||||
// The function must return 1 result, or 2 results, the second of which is an error.
|
||||
//
|
||||
// - Only support func with 1 or 2 return values: (val) OR (val, err)
|
||||
// - Will check args and try convert input args to func args type.
|
||||
func Call2(fn reflect.Value, args []reflect.Value) (reflect.Value, error) {
|
||||
ret, err := Call(fn, args, &CallOpt{
|
||||
TypeChecker: OneOrTwoOutChecker,
|
||||
})
|
||||
if err != nil {
|
||||
return emptyValue, err
|
||||
}
|
||||
|
||||
// func return like: (val, err)
|
||||
if len(ret) == 2 && !ret[1].IsNil() {
|
||||
return ret[0], ret[1].Interface().(error)
|
||||
}
|
||||
return ret[0], nil
|
||||
}
|
||||
|
||||
// Call returns the result of evaluating the first argument as a function.
|
||||
//
|
||||
// - Will check args and try convert input args to func args type.
|
||||
//
|
||||
// from text/template/funcs.go#call
|
||||
func Call(fn reflect.Value, args []reflect.Value, opt *CallOpt) ([]reflect.Value, error) {
|
||||
fn = indirectInterface(fn)
|
||||
if !fn.IsValid() {
|
||||
return nil, fmt.Errorf("call of nil")
|
||||
}
|
||||
|
||||
typ := fn.Type()
|
||||
if typ.Kind() != reflect.Func {
|
||||
return nil, fmt.Errorf("non-function of type %s", typ)
|
||||
}
|
||||
|
||||
if opt == nil {
|
||||
opt = &CallOpt{}
|
||||
}
|
||||
if opt.TypeChecker != nil {
|
||||
if err := opt.TypeChecker(typ); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
numIn := typ.NumIn()
|
||||
var dddType reflect.Type
|
||||
if typ.IsVariadic() {
|
||||
if len(args) < numIn-1 {
|
||||
return nil, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1)
|
||||
}
|
||||
dddType = typ.In(numIn - 1).Elem()
|
||||
} else {
|
||||
if len(args) != numIn {
|
||||
return nil, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn)
|
||||
}
|
||||
}
|
||||
|
||||
// Convert each arg to the type of the function's arg.
|
||||
argv := make([]reflect.Value, len(args))
|
||||
for i, arg := range args {
|
||||
arg = indirectInterface(arg)
|
||||
// Compute the expected type. Clumsy because of variadic.
|
||||
argType := dddType
|
||||
if !typ.IsVariadic() || i < numIn-1 {
|
||||
argType = typ.In(i)
|
||||
}
|
||||
|
||||
var err error
|
||||
if argv[i], err = prepareArg(arg, argType, opt.EnhanceConv); err != nil {
|
||||
return nil, fmt.Errorf("arg %d: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
return SafeCall(fn, argv)
|
||||
}
|
||||
|
||||
// SafeCall2 runs fun.Call(args), and returns the resulting value and error, if
|
||||
// any. If the call panics, the panic value is returned as an error.
|
||||
//
|
||||
// NOTE: Only support func with 1 or 2 return values: (val) OR (val, err)
|
||||
//
|
||||
// from text/template/funcs.go#safeCall
|
||||
func SafeCall2(fun reflect.Value, args []reflect.Value) (val reflect.Value, err error) {
|
||||
ret, err := SafeCall(fun, args)
|
||||
if err != nil {
|
||||
return reflect.Value{}, err
|
||||
}
|
||||
|
||||
// func return like: (val, err)
|
||||
if len(ret) == 2 && !ret[1].IsNil() {
|
||||
return ret[0], ret[1].Interface().(error)
|
||||
}
|
||||
return ret[0], nil
|
||||
}
|
||||
|
||||
// SafeCall runs fun.Call(args), and returns the resulting values, or an error.
|
||||
// If the call panics, the panic value is returned as an error.
|
||||
func SafeCall(fun reflect.Value, args []reflect.Value) (ret []reflect.Value, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if e, ok := r.(error); ok {
|
||||
err = e
|
||||
} else {
|
||||
err = fmt.Errorf("%v", r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
ret = fun.Call(args)
|
||||
return
|
||||
}
|
||||
|
||||
// prepareArg checks if value can be used as an argument of type argType, and
|
||||
// converts an invalid value to appropriate zero if possible.
|
||||
func prepareArg(value reflect.Value, argType reflect.Type, enhanced bool) (reflect.Value, error) {
|
||||
if !value.IsValid() {
|
||||
if !CanBeNil(argType) {
|
||||
return emptyValue, fmt.Errorf("value is nil; should be of type %s", argType)
|
||||
}
|
||||
|
||||
value = reflect.Zero(argType)
|
||||
}
|
||||
|
||||
if value.Type().AssignableTo(argType) {
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// If the argument is an int-like type, and the value is an int-like type, auto-convert.
|
||||
if IsIntLike(value.Kind()) && IsIntLike(argType.Kind()) && value.Type().ConvertibleTo(argType) {
|
||||
value = value.Convert(argType)
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// enhance convert value to argType, support more type: string, int, uint, float, bool
|
||||
if enhanced {
|
||||
return ValueByType(value.Interface(), argType)
|
||||
}
|
||||
return emptyValue, fmt.Errorf("value has type %s; should be %s", value.Type(), argType)
|
||||
}
|
||||
83
vendor/github.com/gookit/goutil/reflects/map.go
generated
vendored
Normal file
83
vendor/github.com/gookit/goutil/reflects/map.go
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
package reflects
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// EachMap process any map data
|
||||
func EachMap(mp reflect.Value, fn func(key, val reflect.Value)) {
|
||||
if fn == nil {
|
||||
return
|
||||
}
|
||||
if mp.Kind() != reflect.Map {
|
||||
panic("only allow map value data")
|
||||
}
|
||||
|
||||
for _, key := range mp.MapKeys() {
|
||||
fn(key, mp.MapIndex(key))
|
||||
}
|
||||
}
|
||||
|
||||
// EachStrAnyMap process any map data as string key and any value
|
||||
func EachStrAnyMap(mp reflect.Value, fn func(key string, val any)) {
|
||||
EachMap(mp, func(key, val reflect.Value) {
|
||||
fn(String(key), val.Interface())
|
||||
})
|
||||
}
|
||||
|
||||
// FlatFunc custom collect handle func
|
||||
type FlatFunc func(path string, val reflect.Value)
|
||||
|
||||
// FlatMap process tree map to flat key-value map.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// {"top": {"sub": "value", "sub2": "value2"} }
|
||||
// ->
|
||||
// {"top.sub": "value", "top.sub2": "value2" }
|
||||
func FlatMap(rv reflect.Value, fn FlatFunc) {
|
||||
if fn == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if rv.Kind() != reflect.Map {
|
||||
panic("only allow flat map data")
|
||||
}
|
||||
flatMap(rv, fn, "")
|
||||
}
|
||||
|
||||
func flatMap(rv reflect.Value, fn FlatFunc, parent string) {
|
||||
for _, key := range rv.MapKeys() {
|
||||
path := String(key)
|
||||
if parent != "" {
|
||||
path = parent + "." + path
|
||||
}
|
||||
|
||||
fv := Indirect(rv.MapIndex(key))
|
||||
switch fv.Kind() {
|
||||
case reflect.Map:
|
||||
flatMap(fv, fn, path)
|
||||
case reflect.Array, reflect.Slice:
|
||||
flatSlice(fv, fn, path)
|
||||
default:
|
||||
fn(path, fv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func flatSlice(rv reflect.Value, fn FlatFunc, parent string) {
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
path := parent + "[" + strconv.Itoa(i) + "]"
|
||||
fv := Indirect(rv.Index(i))
|
||||
|
||||
switch fv.Kind() {
|
||||
case reflect.Map:
|
||||
flatMap(fv, fn, path)
|
||||
case reflect.Array, reflect.Slice:
|
||||
flatSlice(fv, fn, path)
|
||||
default:
|
||||
fn(path, fv)
|
||||
}
|
||||
}
|
||||
}
|
||||
15
vendor/github.com/gookit/goutil/reflects/reflects.go
generated
vendored
15
vendor/github.com/gookit/goutil/reflects/reflects.go
generated
vendored
@@ -1,2 +1,17 @@
|
||||
// Package reflects Provide extends reflect util functions.
|
||||
package reflects
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var emptyValue = reflect.Value{}
|
||||
|
||||
var (
|
||||
anyType = reflect.TypeOf((*any)(nil)).Elem()
|
||||
errorType = reflect.TypeOf((*error)(nil)).Elem()
|
||||
|
||||
fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
|
||||
reflectValueType = reflect.TypeOf((*reflect.Value)(nil)).Elem()
|
||||
)
|
||||
|
||||
61
vendor/github.com/gookit/goutil/reflects/slice.go
generated
vendored
Normal file
61
vendor/github.com/gookit/goutil/reflects/slice.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
package reflects
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// MakeSliceByElem create a new slice by the element type.
|
||||
//
|
||||
// - elType: the type of the element.
|
||||
// - returns: the new slice.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// sl := MakeSliceByElem(reflect.TypeOf(1), 10, 20)
|
||||
// sl.Index(0).SetInt(10)
|
||||
//
|
||||
// // Or use reflect.AppendSlice() merge two slice
|
||||
// // Or use `for` with `reflect.Append()` add elements
|
||||
func MakeSliceByElem(elTyp reflect.Type, len, cap int) reflect.Value {
|
||||
return reflect.MakeSlice(reflect.SliceOf(elTyp), len, cap)
|
||||
}
|
||||
|
||||
// FlatSlice flatten multi-level slice to given depth-level slice.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// FlatSlice([]any{ []any{3, 4}, []any{5, 6} }, 1) // Output: []any{3, 4, 5, 6}
|
||||
//
|
||||
// always return reflect.Value of []any. note: maybe flatSl.Cap != flatSl.Len
|
||||
func FlatSlice(sl reflect.Value, depth int) reflect.Value {
|
||||
items := make([]reflect.Value, 0, sl.Cap())
|
||||
slCap := addSliceItem(sl, depth, func(item reflect.Value) {
|
||||
items = append(items, item)
|
||||
})
|
||||
|
||||
flatSl := reflect.MakeSlice(reflect.SliceOf(anyType), 0, slCap)
|
||||
flatSl = reflect.Append(flatSl, items...)
|
||||
|
||||
return flatSl
|
||||
}
|
||||
|
||||
func addSliceItem(sl reflect.Value, depth int, collector func(item reflect.Value)) (c int) {
|
||||
for i := 0; i < sl.Len(); i++ {
|
||||
v := Elem(sl.Index(i))
|
||||
|
||||
if depth > 0 {
|
||||
if v.Kind() != reflect.Slice {
|
||||
panic(fmt.Sprintf("depth: %d, the value of index %d is not slice", depth, i))
|
||||
}
|
||||
c += addSliceItem(v, depth-1, collector)
|
||||
} else {
|
||||
collector(v)
|
||||
}
|
||||
}
|
||||
|
||||
if depth == 0 {
|
||||
c = sl.Cap()
|
||||
}
|
||||
return c
|
||||
}
|
||||
37
vendor/github.com/gookit/goutil/reflects/type.go
generated
vendored
37
vendor/github.com/gookit/goutil/reflects/type.go
generated
vendored
@@ -2,21 +2,28 @@ package reflects
|
||||
|
||||
import "reflect"
|
||||
|
||||
// BKind base data kind type
|
||||
type BKind uint
|
||||
// BKind base data kind type, alias of reflect.Kind
|
||||
//
|
||||
// Diff with reflect.Kind:
|
||||
// - Int contains all intX types
|
||||
// - Uint contains all uintX types
|
||||
// - Float contains all floatX types
|
||||
// - Array for array and slice types
|
||||
// - Complex contains all complexX types
|
||||
type BKind = reflect.Kind
|
||||
|
||||
// base kinds
|
||||
const (
|
||||
// Int for all intX types
|
||||
Int = BKind(reflect.Int)
|
||||
Int = reflect.Int
|
||||
// Uint for all uintX types
|
||||
Uint = BKind(reflect.Uint)
|
||||
Uint = reflect.Uint
|
||||
// Float for all floatX types
|
||||
Float = BKind(reflect.Float32)
|
||||
Float = reflect.Float32
|
||||
// Array for array,slice types
|
||||
Array = BKind(reflect.Array)
|
||||
Array = reflect.Array
|
||||
// Complex for all complexX types
|
||||
Complex = BKind(reflect.Complex64)
|
||||
Complex = reflect.Complex64
|
||||
)
|
||||
|
||||
// ToBaseKind convert reflect.Kind to base kind
|
||||
@@ -39,7 +46,7 @@ func ToBKind(kind reflect.Kind) BKind {
|
||||
return Array
|
||||
default:
|
||||
// like: string, map, struct, ptr, func, interface ...
|
||||
return BKind(kind)
|
||||
return kind
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +55,10 @@ type Type interface {
|
||||
reflect.Type
|
||||
// BaseKind value
|
||||
BaseKind() BKind
|
||||
// RealType returns a ptr type's real type. otherwise, will return self.
|
||||
RealType() reflect.Type
|
||||
// SafeElem returns a type's element type. otherwise, will return self.
|
||||
SafeElem() reflect.Type
|
||||
}
|
||||
|
||||
type xType struct {
|
||||
@@ -69,3 +80,13 @@ func TypeOf(v any) Type {
|
||||
func (t *xType) BaseKind() BKind {
|
||||
return t.baseKind
|
||||
}
|
||||
|
||||
// RealType returns a ptr type's real type. otherwise, will return self.
|
||||
func (t *xType) RealType() reflect.Type {
|
||||
return TypeReal(t.Type)
|
||||
}
|
||||
|
||||
// SafeElem returns the array, slice, chan, map type's element type. otherwise, will return self.
|
||||
func (t *xType) SafeElem() reflect.Type {
|
||||
return TypeElem(t.Type)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user