Compare commits

...

110 Commits

Author SHA1 Message Date
Kevin Wan
d953675085 chore: add tests (#2960) 2023-03-04 20:34:15 +08:00
yangjinheng
dbc8f9faca timeout writer add hijack 2023-03-04 11:50:04 +00:00
yangjinheng
96998ae570 Update timeouthandler.go 2023-03-04 11:50:04 +00:00
MarkJoyMa
7086fb6dda x 2023-03-04 11:44:47 +00:00
MarkJoyMa
1ad7809fde x 2023-03-04 11:44:47 +00:00
MarkJoyMa
142c46228b x 2023-03-04 11:44:47 +00:00
MarkJoyMa
ba771f8ff1 add ut 2023-03-04 11:44:47 +00:00
MarkJoyMa
f3cf891d4f feat: conf add FillDefault func 2023-03-04 11:44:47 +00:00
zhoumingji
ba71964b16 Fix bug in dartgen: The property 'isEmpty' can't be unconditionally accessed because the receiver can be 'null' 2023-03-04 11:37:38 +00:00
zhoumingji
97ada59175 Fix bug in dartgen: Increase the processing logic when route.RequestType is empty 2023-03-04 04:31:27 +00:00
cui fliter
b41ccc5992 fix functiom name
Signed-off-by: cui fliter <imcusg@gmail.com>
2023-03-04 04:29:19 +00:00
dependabot[bot]
e23f421976 chore(deps): bump k8s.io/client-go from 0.26.1 to 0.26.2 (#2955)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.26.1 to 0.26.2.
- [Release notes](https://github.com/kubernetes/client-go/releases)
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.26.1...v0.26.2)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-04 12:28:25 +08:00
Kevin Wan
dc5b8dd716 feat: support grpc client keepalive config (#2950) 2023-03-03 23:40:17 +08:00
tanglihao
a40d8b0684 fix code format style use const config.DefaultFormat 2023-03-03 14:58:18 +00:00
tanglihao
cb39b5836f fix log name conflict 2023-03-03 14:58:18 +00:00
dependabot[bot]
4988f2a4da chore(deps): bump k8s.io/apimachinery from 0.26.1 to 0.26.2 (#2954)
Bumps [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) from 0.26.1 to 0.26.2.
- [Release notes](https://github.com/kubernetes/apimachinery/releases)
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.26.1...v0.26.2)

---
updated-dependencies:
- dependency-name: k8s.io/apimachinery
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-03 22:56:07 +08:00
anqiansong
7ca89a85ab format code 2023-03-03 07:11:13 +00:00
anqiansong
1ac2384750 remove unused code 2023-03-03 07:11:13 +00:00
anqiansong
0e040ec5b4 remove unused code 2023-03-03 07:11:13 +00:00
anqiansong
4bc1b78a91 Fix #2879 2023-03-03 07:11:13 +00:00
qiying.wang
148afcf1a7 chore: remove redundant prefix of "error: " in error creation 2023-03-02 12:46:19 +00:00
Kevin Wan
1cd1b17f70 fix: security #9 (#2949)
* fix: security #9

* fix: missing packages

* chore: update deps
2023-03-02 16:31:39 +08:00
dependabot[bot]
59c110688d chore(deps): bump github.com/pelletier/go-toml/v2 from 2.0.6 to 2.0.7 (#2943)
Bumps [github.com/pelletier/go-toml/v2](https://github.com/pelletier/go-toml) from 2.0.6 to 2.0.7.
- [Release notes](https://github.com/pelletier/go-toml/releases)
- [Changelog](https://github.com/pelletier/go-toml/blob/v2/.goreleaser.yaml)
- [Commits](https://github.com/pelletier/go-toml/compare/v2.0.6...v2.0.7)

---
updated-dependencies:
- dependency-name: github.com/pelletier/go-toml/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-02 14:22:00 +08:00
dependabot[bot]
6a25323467 chore(deps): bump go.opentelemetry.io/otel/exporters/jaeger (#2942)
Bumps [go.opentelemetry.io/otel/exporters/jaeger](https://github.com/open-telemetry/opentelemetry-go) from 1.13.0 to 1.14.0.
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.13.0...v1.14.0)

---
updated-dependencies:
- dependency-name: go.opentelemetry.io/otel/exporters/jaeger
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-02 13:51:17 +08:00
dependabot[bot]
6aeb3dfb1c chore(deps): bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp (#2941)
Bumps [go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp](https://github.com/open-telemetry/opentelemetry-go) from 1.13.0 to 1.14.0.
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.13.0...v1.14.0)

---
updated-dependencies:
- dependency-name: go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-02 12:55:25 +08:00
qiying.wang
0cb61b9a9c chore: add tests for logc debug 2023-03-02 04:38:54 +00:00
qiying.wang
10d263395c feat: add debug log for logc 2023-03-02 04:38:54 +00:00
kevin
d65801f258 chore: add comments 2023-03-02 04:32:24 +00:00
kevin
eaac0ba8de chore: add more tests 2023-03-02 04:32:24 +00:00
kevin
b449f2f39e chore: add more tests 2023-03-02 04:32:24 +00:00
kevin
c57b0b8f90 feat: check key overwritten 2023-03-02 04:32:24 +00:00
dependabot[bot]
696406b887 chore(deps): bump go.opentelemetry.io/otel/exporters/zipkin (#2940)
Bumps [go.opentelemetry.io/otel/exporters/zipkin](https://github.com/open-telemetry/opentelemetry-go) from 1.13.0 to 1.14.0.
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.13.0...v1.14.0)

---
updated-dependencies:
- dependency-name: go.opentelemetry.io/otel/exporters/zipkin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-02 12:26:58 +08:00
dependabot[bot]
cc1779936e chore(deps): bump github.com/jackc/pgx/v5 from 5.2.0 to 5.3.1 (#2939)
Bumps [github.com/jackc/pgx/v5](https://github.com/jackc/pgx) from 5.2.0 to 5.3.1.
- [Release notes](https://github.com/jackc/pgx/releases)
- [Changelog](https://github.com/jackc/pgx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jackc/pgx/compare/v5.2.0...v5.3.1)

---
updated-dependencies:
- dependency-name: github.com/jackc/pgx/v5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-02 12:11:53 +08:00
Kevin Wan
de4924a274 fix: config map cannot handle case-insensitive keys. (#2932)
* fix: #2922

* chore: rename const

* feat: support anonymous map field

* feat: support anonymous map field
2023-02-28 23:32:08 +08:00
kevin
2b08e0510c chore: go mod tidy and update deps 2023-02-28 04:38:56 +00:00
kevin
afac48a8ea chore: go mod tidy and update deps 2023-02-28 04:38:56 +00:00
dependabot[bot]
a50b604dc9 chore(deps): bump github.com/jhump/protoreflect from 1.14.1 to 1.15.0
Bumps [github.com/jhump/protoreflect](https://github.com/jhump/protoreflect) from 1.14.1 to 1.15.0.
- [Release notes](https://github.com/jhump/protoreflect/releases)
- [Commits](https://github.com/jhump/protoreflect/compare/v1.14.1...v1.15.0)

---
updated-dependencies:
- dependency-name: github.com/jhump/protoreflect
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-28 03:19:53 +00:00
dependabot[bot]
eda44b6ae8 chore(deps): bump github.com/stretchr/testify from 1.8.1 to 1.8.2
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.1 to 1.8.2.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.8.1...v1.8.2)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-28 03:19:04 +00:00
Kevin Wan
284331b7b1 fix: #2899, using autoscaling/v2beta2 instead of v2beta1 (#2900)
* fix: #2899, using autoscaling/v2 instead of v2beta1

* chore: change hpa definition

---------

Co-authored-by: kevin.wan <kevin.wan@yijinin.com>
2023-02-26 22:32:27 +08:00
Kevin Wan
66be213346 chore: refine rest validator (#2928)
* chore: refine rest validator

* chore: add more tests

* chore: reformat code

* chore: add comments
2023-02-26 21:58:58 +08:00
Qiying Wang
92c8899f47 feat: add configurable validator for httpx.Parse (#2923)
Co-authored-by: qiying.wang <qiying.wang@highlight.mobi>
2023-02-26 20:40:22 +08:00
Kevin Wan
238c830f17 fix: timeout not working if greater than global rest timeout (#2926) 2023-02-26 20:22:20 +08:00
raymonder jin
ace125f189 del unnecessary blank 2023-02-26 04:59:23 +00:00
Kevin Wan
a5e5f04bcf chore: reformat code (#2925) 2023-02-26 09:35:59 +08:00
chenquan
3bc40d9eaf fix: fixed the bug that old trace instances may be fetched 2023-02-22 13:01:22 +00:00
yiwu
133c40ac1c Pgx (#2902)
* change postgres driver  to  pgx

* modified:   go.mod
	modified:   go.sum

* chore: tidy go.sum

---------

Co-authored-by: Kevin Wan <wanjunfeng@gmail.com>
2023-02-22 14:11:49 +08:00
xiandong
eaaf87cdeb rm parseErr when kindJaeger 2023-02-22 05:41:07 +00:00
xiandong
6dbcfb5e5d rm kindJaegerUdp 2023-02-22 05:41:07 +00:00
xiandong
16a5f30b0c add parseEndpoint 2023-02-22 05:41:07 +00:00
xiandong
4e6d800877 add parseEndpoint 2023-02-22 05:41:07 +00:00
xiandong
af19addf47 add test for Endpoint of kindJaegerUdp 2023-02-22 05:41:07 +00:00
xiandong
ebc425b797 add test for Endpoint of kindJaegerUdp 2023-02-22 05:41:07 +00:00
xiandong
b6bedcd522 add kindJaegerUdp 2023-02-22 05:41:07 +00:00
xiandong
12060c9c0c opentelemetry support AgentHost, AgentPort 2023-02-22 05:41:07 +00:00
xiandong
e575bf8317 add jaeger.WithAgentEndpoint 2023-02-22 05:41:07 +00:00
strong
0fe84b225c fix(goctl): unsupported database type: bpchar (#2840) 2023-02-21 19:40:29 +08:00
dependabot[bot]
33af0745a0 chore(deps): bump golang.org/x/net from 0.5.0 to 0.7.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.5.0 to 0.7.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/compare/v0.5.0...v0.7.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-21 06:19:21 +00:00
dependabot[bot]
1d0265a77e chore(deps): bump github.com/golang-jwt/jwt/v4 from 4.4.3 to 4.5.0 (#2904)
Bumps [github.com/golang-jwt/jwt/v4](https://github.com/golang-jwt/jwt) from 4.4.3 to 4.5.0.
- [Release notes](https://github.com/golang-jwt/jwt/releases)
- [Changelog](https://github.com/golang-jwt/jwt/blob/main/VERSION_HISTORY.md)
- [Commits](https://github.com/golang-jwt/jwt/compare/v4.4.3...v4.5.0)

---
updated-dependencies:
- dependency-name: github.com/golang-jwt/jwt/v4
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-21 14:16:47 +08:00
Kevin Wan
03fe036204 chore: reformat code (#2903) 2023-02-20 23:37:05 +08:00
anqiansong
03d073a884 feat: Add request.ts (#2901)
* Add request.ts

* Update comments

* Refactor request filename
2023-02-20 22:54:25 +08:00
cong
64ab00e8e3 refactor: simplify sqlx fail fast ping and simplify miniredis setup in test (#2897)
* chore(redistest): simplify miniredis setup in test

* refactor(sqlx): simplify sqlx fail fast ping

* chore: close connection if not available
2023-02-19 17:18:19 +08:00
Kevin Wan
d113e1352c Update readme-cn.md 2023-02-17 14:48:41 +08:00
fondoger
32e3116ee3 Fix bug in dart api gen: path parameter is not replaced 2023-02-16 15:24:51 +00:00
Kevin Wan
1dd18e2329 Update readme-cn.md 2023-02-16 21:51:17 +08:00
dependabot[bot]
44b2389f9c chore(deps): bump go.uber.org/goleak from 1.2.0 to 1.2.1 (#2883)
Bumps [go.uber.org/goleak](https://github.com/uber-go/goleak) from 1.2.0 to 1.2.1.
- [Release notes](https://github.com/uber-go/goleak/releases)
- [Changelog](https://github.com/uber-go/goleak/blob/master/CHANGELOG.md)
- [Commits](https://github.com/uber-go/goleak/compare/v1.2.0...v1.2.1)

---
updated-dependencies:
- dependency-name: go.uber.org/goleak
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-16 21:18:00 +08:00
Kevin Wan
8bc34c58f4 fix: test failures (#2892)
Co-authored-by: kevin.wan <kevin.wan@yijinin.com>
2023-02-16 19:45:34 +08:00
fondoger
5756627904 Fix Dart API generation bugs; Add ability to generate API for path parameters (#2887)
* Fix bug in dartgen: Import path should match the generated api filename

* Use Route.HandlerName as generated dart API function name

Reasons:
- There is bug when using url path name as function name, because it may have invalid characters such as ":"
- Switching to HandlerName aligns with other languages such as typescript generation

* [DartGen] Add ability to generate api for url path parameters such as /path/:param
2023-02-16 15:19:46 +08:00
Kevin Wan
cddf3875cf refactor: simplify stringx.Replacer, and avoid potential infinite loops (#2877)
* simplify replace

* backup

* refactor: simplify stringx.Replacer

* chore: add comments and const

* chore: add more tests

* chore: rename variable
2023-02-14 10:18:02 +08:00
dependabot[bot]
9be17a2d28 chore(deps): bump go.mongodb.org/mongo-driver from 1.11.1 to 1.11.2
Bumps [go.mongodb.org/mongo-driver](https://github.com/mongodb/mongo-go-driver) from 1.11.1 to 1.11.2.
- [Release notes](https://github.com/mongodb/mongo-go-driver/releases)
- [Commits](https://github.com/mongodb/mongo-go-driver/compare/v1.11.1...v1.11.2)

---
updated-dependencies:
- dependency-name: go.mongodb.org/mongo-driver
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 23:39:41 +00:00
Kevin Wan
b8a86e2135 Update readme-cn.md 2023-02-13 22:03:22 +08:00
Kevin Wan
072db116c3 chore: refactor (#2875) 2023-02-12 22:20:36 +08:00
dahaihu
cacd5dc91a fix Replacer suffix match, and add test case (#2867)
* fix: replace shoud replace the longest match

* feat: revert bytes.Buffer to strings.Builder

* fix: loop reset nextStart

* feat: add node longest match test

* feat: add replacer suffix match test case

* feat: multiple match

* fix: partial match ends

* fix: replace look back upon error

* feat: rm unnecessary branch

---------

Co-authored-by: hudahai <hscxrzs@gmail.com>
Co-authored-by: hushichang <hushichang@sensetime.com>
2023-02-12 21:04:35 +08:00
Kevin Wan
3736dacf1e chore: add more tests (#2873) 2023-02-12 20:32:56 +08:00
Kevin Wan
434973c206 fix: test failure (#2874) 2023-02-12 20:08:02 +08:00
Mikael
84f9863b63 only unmashal public variables (#2872)
* only unmashal public variables

* only unmashal public variables

* only unmashal public variables

* only unmashal public variables
2023-02-12 19:53:20 +08:00
Kevin Wan
99a7e6600d feat: use dependabot for goctl (#2869)
* feat: use dependabot for goctl

* chore: add more tests

* chore: remove temp file
2023-02-11 16:32:28 +08:00
chen quan
ea7dab3d26 feat(sqlx): error log print traceId and spanId (#2845) 2023-02-11 16:12:14 +08:00
Kevin Wan
d7d6eccce6 chore: remove clickhouse, added to zero-contrib (#2848) 2023-02-11 15:28:59 +08:00
Kevin Wan
0a5a26385d chore: add more tests (#2866)
* chore: add more tests

* chore: add more tests

* chore: fix test failure
2023-02-11 14:21:39 +08:00
hudahai
62e59837c6 fix: loop reset nextStart 2023-02-10 04:26:50 +00:00
hudahai
981d7dab13 feat: revert bytes.Buffer to strings.Builder 2023-02-10 04:26:50 +00:00
hudahai
d9a732a273 fix: replace shoud replace the longest match 2023-02-10 04:26:50 +00:00
dependabot[bot]
b6f1bce695 chore(deps): bump go.opentelemetry.io/otel/exporters/jaeger (#2858)
Bumps [go.opentelemetry.io/otel/exporters/jaeger](https://github.com/open-telemetry/opentelemetry-go) from 1.12.0 to 1.13.0.
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.12.0...v1.13.0)

---
updated-dependencies:
- dependency-name: go.opentelemetry.io/otel/exporters/jaeger
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-10 10:41:35 +08:00
dependabot[bot]
0988c4148f chore(deps): bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp
Bumps [go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp](https://github.com/open-telemetry/opentelemetry-go) from 1.12.0 to 1.13.0.
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.12.0...v1.13.0)

---
updated-dependencies:
- dependency-name: go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-10 01:49:56 +00:00
dependabot[bot]
165133b91b chore(deps): bump go.opentelemetry.io/otel/exporters/zipkin (#2857)
Bumps [go.opentelemetry.io/otel/exporters/zipkin](https://github.com/open-telemetry/opentelemetry-go) from 1.12.0 to 1.13.0.
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.12.0...v1.13.0)

---
updated-dependencies:
- dependency-name: go.opentelemetry.io/otel/exporters/zipkin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-09 22:23:04 +08:00
dependabot[bot]
cd8081c567 chore(deps): bump go.opentelemetry.io/otel/trace from 1.12.0 to 1.13.0 (#2860)
Bumps [go.opentelemetry.io/otel/trace](https://github.com/open-telemetry/opentelemetry-go) from 1.12.0 to 1.13.0.
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.12.0...v1.13.0)

---
updated-dependencies:
- dependency-name: go.opentelemetry.io/otel/trace
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-09 20:23:04 +08:00
dependabot[bot]
e40a089086 chore(deps): bump google.golang.org/grpc from 1.52.3 to 1.53.0 (#2856)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.52.3 to 1.53.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.52.3...v1.53.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-09 13:38:23 +08:00
Kevin Wan
d9780fb2a6 Update readme-cn.md 2023-02-08 12:49:33 +08:00
dependabot[bot]
2c8ae994cf chore(deps): bump golang.org/x/sys from 0.4.0 to 0.5.0 (#2854)
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.4.0 to 0.5.0.
- [Release notes](https://github.com/golang/sys/releases)
- [Commits](https://github.com/golang/sys/compare/v0.4.0...v0.5.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-08 12:38:11 +08:00
dependabot[bot]
67a046b554 chore(deps): bump github.com/ClickHouse/clickhouse-go/v2 (#2838)
Bumps [github.com/ClickHouse/clickhouse-go/v2](https://github.com/ClickHouse/clickhouse-go) from 2.5.1 to 2.6.0.
- [Release notes](https://github.com/ClickHouse/clickhouse-go/releases)
- [Changelog](https://github.com/ClickHouse/clickhouse-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ClickHouse/clickhouse-go/compare/v2.5.1...2.6.0)

---
updated-dependencies:
- dependency-name: github.com/ClickHouse/clickhouse-go/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-05 14:55:26 +08:00
Kevin Wan
a019a1f59f fix: conf anonymous overlay problem (#2847) 2023-02-05 14:40:57 +08:00
Kevin Wan
aed312f3c0 Update readme-cn.md 2023-01-31 23:12:17 +08:00
Kevin Wan
58138fd56c Chore/rewire (#2836)
* fix: problem on name overlaping in config (#2820)

* chore: fix missing funcs on windows (#2825)

* chore: add more tests (#2812)

* chore: add more tests

* chore: add more tests

* chore: add more tests (#2814)

* chore: add more tests (#2815)

* chore: add more tests

* chore: add more tests

* chore: add more tests

* chore: add more tests

* chore: add more tests

* chore: add more tests

* feat: upgrade go to v1.18 (#2817)

* feat: upgrade go to v1.18

* feat: upgrade go to v1.18

* chore: change interface{} to any (#2818)

* chore: change interface{} to any

* chore: update goctl version to 1.5.0

* chore: update goctl deps

* chore: update goctl interface{} to any (#2819)

* chore: update goctl interface{} to any

* chore: update goctl interface{} to any

* chore(deps): bump google.golang.org/grpc from 1.52.0 to 1.52.3 (#2823)

* support custom maxBytes in API file (#2822)

* feat: mapreduce generic version (#2827)

* feat: mapreduce generic version

* fix: gateway mr type issue

---------

Co-authored-by: kevin.wan <kevin.wan@yijinin.com>

* feat: add MustNewRedis (#2824)

* feat: add MustNewRedis

* feat: add MustNewRedis

* feat: add MustNewRedis

* x

* x

* fix ut

* x

* x

* x

* x

* x

* chore: improve codecov (#2828)

* feat: converge grpc interceptor processing (#2830)

* feat: converge grpc interceptor processing

* x

* x

* chore(deps): bump go.opentelemetry.io/otel/exporters/zipkin (#2831)

* chore(deps): bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp (#2833)

Bumps [go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp](https://github.com/open-telemetry/opentelemetry-go) from 1.11.2 to 1.12.0.
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.11.2...v1.12.0)

---
updated-dependencies:
- dependency-name: go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump go.opentelemetry.io/otel/exporters/jaeger (#2832)

Bumps [go.opentelemetry.io/otel/exporters/jaeger](https://github.com/open-telemetry/opentelemetry-go) from 1.11.2 to 1.12.0.
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.11.2...v1.12.0)

---
updated-dependencies:
- dependency-name: go.opentelemetry.io/otel/exporters/jaeger
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Xiaoju Jiang <44432198+jiang4869@users.noreply.github.com>
Co-authored-by: kevin.wan <kevin.wan@yijinin.com>
Co-authored-by: MarkJoyMa <64180138+MarkJoyMa@users.noreply.github.com>
2023-01-31 13:58:22 +08:00
dependabot[bot]
f2588b238f chore(deps): bump go.opentelemetry.io/otel/exporters/jaeger (#2832)
Bumps [go.opentelemetry.io/otel/exporters/jaeger](https://github.com/open-telemetry/opentelemetry-go) from 1.11.2 to 1.12.0.
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.11.2...v1.12.0)

---
updated-dependencies:
- dependency-name: go.opentelemetry.io/otel/exporters/jaeger
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-31 11:04:39 +08:00
dependabot[bot]
cc5ae722a2 chore(deps): bump go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp (#2833)
Bumps [go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp](https://github.com/open-telemetry/opentelemetry-go) from 1.11.2 to 1.12.0.
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.11.2...v1.12.0)

---
updated-dependencies:
- dependency-name: go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-31 09:21:08 +08:00
dependabot[bot]
1ee61709d9 chore(deps): bump go.opentelemetry.io/otel/exporters/zipkin (#2831) 2023-01-31 09:06:24 +08:00
MarkJoyMa
dd117ce9cf feat: converge grpc interceptor processing (#2830)
* feat: converge grpc interceptor processing

* x

* x
2023-01-30 15:48:50 +08:00
Kevin Wan
3c0dc8435e chore: improve codecov (#2828) 2023-01-29 21:39:54 +08:00
MarkJoyMa
fde05ccb28 feat: add MustNewRedis (#2824)
* feat: add MustNewRedis

* feat: add MustNewRedis

* feat: add MustNewRedis

* x

* x

* fix ut

* x

* x

* x

* x

* x
2023-01-29 18:03:05 +08:00
Kevin Wan
464ed51728 feat: mapreduce generic version (#2827)
* feat: mapreduce generic version

* fix: gateway mr type issue

---------

Co-authored-by: kevin.wan <kevin.wan@yijinin.com>
2023-01-29 18:01:23 +08:00
Xiaoju Jiang
413ee919e6 support custom maxBytes in API file (#2822) 2023-01-29 10:43:00 +08:00
Kevin Wan
35b9568657 chore: fix missing funcs on windows (#2825) 2023-01-28 22:45:36 +08:00
dependabot[bot]
167d76b46d chore(deps): bump google.golang.org/grpc from 1.52.0 to 1.52.3 (#2823) 2023-01-28 16:48:30 +08:00
Kevin Wan
ab9eeff500 fix: problem on name overlaping in config (#2820) 2023-01-24 21:14:48 +08:00
Kevin Wan
eab904af64 chore: update goctl interface{} to any (#2819)
* chore: update goctl interface{} to any

* chore: update goctl interface{} to any
2023-01-24 17:51:03 +08:00
Kevin Wan
ae87114282 chore: change interface{} to any (#2818)
* chore: change interface{} to any

* chore: update goctl version to 1.5.0

* chore: update goctl deps
2023-01-24 16:32:02 +08:00
Kevin Wan
7e0ac77139 feat: upgrade go to v1.18 (#2817)
* feat: upgrade go to v1.18

* feat: upgrade go to v1.18
2023-01-24 15:47:01 +08:00
Kevin Wan
696da4efee chore: add more tests (#2815)
* chore: add more tests

* chore: add more tests

* chore: add more tests

* chore: add more tests

* chore: add more tests

* chore: add more tests
2023-01-24 13:43:13 +08:00
Kevin Wan
ceab564429 chore: add more tests (#2814) 2023-01-24 12:03:05 +08:00
Kevin Wan
4bd8025c5b chore: add more tests (#2812)
* chore: add more tests

* chore: add more tests
2023-01-23 23:27:47 +08:00
318 changed files with 5210 additions and 3613 deletions

View File

@@ -9,3 +9,7 @@ updates:
directory: "/" # Location of package manifests directory: "/" # Location of package manifests
schedule: schedule:
interval: "daily" interval: "daily"
- package-ecosystem: "gomod" # See documentation for possible values
directory: "/tools/goctl" # Location of package manifests
schedule:
interval: "daily"

View File

@@ -17,7 +17,7 @@ jobs:
- name: Set up Go 1.x - name: Set up Go 1.x
uses: actions/setup-go@v3 uses: actions/setup-go@v3
with: with:
go-version: ^1.16 go-version: ^1.18
check-latest: true check-latest: true
cache: true cache: true
id: go id: go
@@ -48,8 +48,8 @@ jobs:
- name: Set up Go 1.x - name: Set up Go 1.x
uses: actions/setup-go@v3 uses: actions/setup-go@v3
with: with:
# use 1.16 to guarantee Go 1.16 compatibility # use 1.18 to guarantee Go 1.18 compatibility
go-version: 1.16 go-version: 1.18
check-latest: true check-latest: true
cache: true cache: true

2
.gitignore vendored
View File

@@ -11,7 +11,7 @@
!api !api
# ignore # ignore
.idea **/.idea
**/.DS_Store **/.DS_Store
**/logs **/logs

View File

@@ -30,7 +30,7 @@ type (
Cache struct { Cache struct {
name string name string
lock sync.Mutex lock sync.Mutex
data map[string]interface{} data map[string]any
expire time.Duration expire time.Duration
timingWheel *TimingWheel timingWheel *TimingWheel
lruCache lru lruCache lru
@@ -43,7 +43,7 @@ type (
// NewCache returns a Cache with given expire. // NewCache returns a Cache with given expire.
func NewCache(expire time.Duration, opts ...CacheOption) (*Cache, error) { func NewCache(expire time.Duration, opts ...CacheOption) (*Cache, error) {
cache := &Cache{ cache := &Cache{
data: make(map[string]interface{}), data: make(map[string]any),
expire: expire, expire: expire,
lruCache: emptyLruCache, lruCache: emptyLruCache,
barrier: syncx.NewSingleFlight(), barrier: syncx.NewSingleFlight(),
@@ -59,7 +59,7 @@ func NewCache(expire time.Duration, opts ...CacheOption) (*Cache, error) {
} }
cache.stats = newCacheStat(cache.name, cache.size) cache.stats = newCacheStat(cache.name, cache.size)
timingWheel, err := NewTimingWheel(time.Second, slots, func(k, v interface{}) { timingWheel, err := NewTimingWheel(time.Second, slots, func(k, v any) {
key, ok := k.(string) key, ok := k.(string)
if !ok { if !ok {
return return
@@ -85,7 +85,7 @@ func (c *Cache) Del(key string) {
} }
// Get returns the item with the given key from c. // Get returns the item with the given key from c.
func (c *Cache) Get(key string) (interface{}, bool) { func (c *Cache) Get(key string) (any, bool) {
value, ok := c.doGet(key) value, ok := c.doGet(key)
if ok { if ok {
c.stats.IncrementHit() c.stats.IncrementHit()
@@ -97,12 +97,12 @@ func (c *Cache) Get(key string) (interface{}, bool) {
} }
// Set sets value into c with key. // Set sets value into c with key.
func (c *Cache) Set(key string, value interface{}) { func (c *Cache) Set(key string, value any) {
c.SetWithExpire(key, value, c.expire) c.SetWithExpire(key, value, c.expire)
} }
// SetWithExpire sets value into c with key and expire with the given value. // SetWithExpire sets value into c with key and expire with the given value.
func (c *Cache) SetWithExpire(key string, value interface{}, expire time.Duration) { func (c *Cache) SetWithExpire(key string, value any, expire time.Duration) {
c.lock.Lock() c.lock.Lock()
_, ok := c.data[key] _, ok := c.data[key]
c.data[key] = value c.data[key] = value
@@ -120,14 +120,14 @@ func (c *Cache) SetWithExpire(key string, value interface{}, expire time.Duratio
// Take returns the item with the given key. // Take returns the item with the given key.
// If the item is in c, return it directly. // If the item is in c, return it directly.
// If not, use fetch method to get the item, set into c and return it. // If not, use fetch method to get the item, set into c and return it.
func (c *Cache) Take(key string, fetch func() (interface{}, error)) (interface{}, error) { func (c *Cache) Take(key string, fetch func() (any, error)) (any, error) {
if val, ok := c.doGet(key); ok { if val, ok := c.doGet(key); ok {
c.stats.IncrementHit() c.stats.IncrementHit()
return val, nil return val, nil
} }
var fresh bool var fresh bool
val, err := c.barrier.Do(key, func() (interface{}, error) { val, err := c.barrier.Do(key, func() (any, error) {
// because O(1) on map search in memory, and fetch is an IO query // because O(1) on map search in memory, and fetch is an IO query
// so we do double check, cache might be taken by another call // so we do double check, cache might be taken by another call
if val, ok := c.doGet(key); ok { if val, ok := c.doGet(key); ok {
@@ -157,7 +157,7 @@ func (c *Cache) Take(key string, fetch func() (interface{}, error)) (interface{}
return val, nil return val, nil
} }
func (c *Cache) doGet(key string) (interface{}, bool) { func (c *Cache) doGet(key string) (any, bool) {
c.lock.Lock() c.lock.Lock()
defer c.lock.Unlock() defer c.lock.Unlock()

View File

@@ -52,7 +52,7 @@ func TestCacheTake(t *testing.T) {
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
wg.Add(1) wg.Add(1)
go func() { go func() {
cache.Take("first", func() (interface{}, error) { cache.Take("first", func() (any, error) {
atomic.AddInt32(&count, 1) atomic.AddInt32(&count, 1)
time.Sleep(time.Millisecond * 100) time.Sleep(time.Millisecond * 100)
return "first element", nil return "first element", nil
@@ -76,7 +76,7 @@ func TestCacheTakeExists(t *testing.T) {
wg.Add(1) wg.Add(1)
go func() { go func() {
cache.Set("first", "first element") cache.Set("first", "first element")
cache.Take("first", func() (interface{}, error) { cache.Take("first", func() (any, error) {
atomic.AddInt32(&count, 1) atomic.AddInt32(&count, 1)
time.Sleep(time.Millisecond * 100) time.Sleep(time.Millisecond * 100)
return "first element", nil return "first element", nil
@@ -99,7 +99,7 @@ func TestCacheTakeError(t *testing.T) {
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
wg.Add(1) wg.Add(1)
go func() { go func() {
_, err := cache.Take("first", func() (interface{}, error) { _, err := cache.Take("first", func() (any, error) {
atomic.AddInt32(&count, 1) atomic.AddInt32(&count, 1)
time.Sleep(time.Millisecond * 100) time.Sleep(time.Millisecond * 100)
return "", errDummy return "", errDummy

View File

@@ -5,7 +5,7 @@ import "sync"
// A Queue is a FIFO queue. // A Queue is a FIFO queue.
type Queue struct { type Queue struct {
lock sync.Mutex lock sync.Mutex
elements []interface{} elements []any
size int size int
head int head int
tail int tail int
@@ -15,7 +15,7 @@ type Queue struct {
// NewQueue returns a Queue object. // NewQueue returns a Queue object.
func NewQueue(size int) *Queue { func NewQueue(size int) *Queue {
return &Queue{ return &Queue{
elements: make([]interface{}, size), elements: make([]any, size),
size: size, size: size,
} }
} }
@@ -30,12 +30,12 @@ func (q *Queue) Empty() bool {
} }
// Put puts element into q at the last position. // Put puts element into q at the last position.
func (q *Queue) Put(element interface{}) { func (q *Queue) Put(element any) {
q.lock.Lock() q.lock.Lock()
defer q.lock.Unlock() defer q.lock.Unlock()
if q.head == q.tail && q.count > 0 { if q.head == q.tail && q.count > 0 {
nodes := make([]interface{}, len(q.elements)+q.size) nodes := make([]any, len(q.elements)+q.size)
copy(nodes, q.elements[q.head:]) copy(nodes, q.elements[q.head:])
copy(nodes[len(q.elements)-q.head:], q.elements[:q.head]) copy(nodes[len(q.elements)-q.head:], q.elements[:q.head])
q.head = 0 q.head = 0
@@ -49,7 +49,7 @@ func (q *Queue) Put(element interface{}) {
} }
// Take takes the first element out of q if not empty. // Take takes the first element out of q if not empty.
func (q *Queue) Take() (interface{}, bool) { func (q *Queue) Take() (any, bool) {
q.lock.Lock() q.lock.Lock()
defer q.lock.Unlock() defer q.lock.Unlock()

View File

@@ -4,7 +4,7 @@ import "sync"
// A Ring can be used as fixed size ring. // A Ring can be used as fixed size ring.
type Ring struct { type Ring struct {
elements []interface{} elements []any
index int index int
lock sync.RWMutex lock sync.RWMutex
} }
@@ -16,12 +16,12 @@ func NewRing(n int) *Ring {
} }
return &Ring{ return &Ring{
elements: make([]interface{}, n), elements: make([]any, n),
} }
} }
// Add adds v into r. // Add adds v into r.
func (r *Ring) Add(v interface{}) { func (r *Ring) Add(v any) {
r.lock.Lock() r.lock.Lock()
defer r.lock.Unlock() defer r.lock.Unlock()
@@ -30,7 +30,7 @@ func (r *Ring) Add(v interface{}) {
} }
// Take takes all items from r. // Take takes all items from r.
func (r *Ring) Take() []interface{} { func (r *Ring) Take() []any {
r.lock.RLock() r.lock.RLock()
defer r.lock.RUnlock() defer r.lock.RUnlock()
@@ -43,7 +43,7 @@ func (r *Ring) Take() []interface{} {
size = r.index size = r.index
} }
elements := make([]interface{}, size) elements := make([]any, size)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
elements[i] = r.elements[(start+i)%len(r.elements)] elements[i] = r.elements[(start+i)%len(r.elements)]
} }

View File

@@ -19,7 +19,7 @@ func TestRingLess(t *testing.T) {
ring.Add(i) ring.Add(i)
} }
elements := ring.Take() elements := ring.Take()
assert.ElementsMatch(t, []interface{}{0, 1, 2}, elements) assert.ElementsMatch(t, []any{0, 1, 2}, elements)
} }
func TestRingMore(t *testing.T) { func TestRingMore(t *testing.T) {
@@ -28,7 +28,7 @@ func TestRingMore(t *testing.T) {
ring.Add(i) ring.Add(i)
} }
elements := ring.Take() elements := ring.Take()
assert.ElementsMatch(t, []interface{}{6, 7, 8, 9, 10}, elements) assert.ElementsMatch(t, []any{6, 7, 8, 9, 10}, elements)
} }
func TestRingAdd(t *testing.T) { func TestRingAdd(t *testing.T) {

View File

@@ -14,20 +14,20 @@ type SafeMap struct {
lock sync.RWMutex lock sync.RWMutex
deletionOld int deletionOld int
deletionNew int deletionNew int
dirtyOld map[interface{}]interface{} dirtyOld map[any]any
dirtyNew map[interface{}]interface{} dirtyNew map[any]any
} }
// NewSafeMap returns a SafeMap. // NewSafeMap returns a SafeMap.
func NewSafeMap() *SafeMap { func NewSafeMap() *SafeMap {
return &SafeMap{ return &SafeMap{
dirtyOld: make(map[interface{}]interface{}), dirtyOld: make(map[any]any),
dirtyNew: make(map[interface{}]interface{}), dirtyNew: make(map[any]any),
} }
} }
// Del deletes the value with the given key from m. // Del deletes the value with the given key from m.
func (m *SafeMap) Del(key interface{}) { func (m *SafeMap) Del(key any) {
m.lock.Lock() m.lock.Lock()
if _, ok := m.dirtyOld[key]; ok { if _, ok := m.dirtyOld[key]; ok {
delete(m.dirtyOld, key) delete(m.dirtyOld, key)
@@ -42,21 +42,21 @@ func (m *SafeMap) Del(key interface{}) {
} }
m.dirtyOld = m.dirtyNew m.dirtyOld = m.dirtyNew
m.deletionOld = m.deletionNew m.deletionOld = m.deletionNew
m.dirtyNew = make(map[interface{}]interface{}) m.dirtyNew = make(map[any]any)
m.deletionNew = 0 m.deletionNew = 0
} }
if m.deletionNew >= maxDeletion && len(m.dirtyNew) < copyThreshold { if m.deletionNew >= maxDeletion && len(m.dirtyNew) < copyThreshold {
for k, v := range m.dirtyNew { for k, v := range m.dirtyNew {
m.dirtyOld[k] = v m.dirtyOld[k] = v
} }
m.dirtyNew = make(map[interface{}]interface{}) m.dirtyNew = make(map[any]any)
m.deletionNew = 0 m.deletionNew = 0
} }
m.lock.Unlock() m.lock.Unlock()
} }
// Get gets the value with the given key from m. // Get gets the value with the given key from m.
func (m *SafeMap) Get(key interface{}) (interface{}, bool) { func (m *SafeMap) Get(key any) (any, bool) {
m.lock.RLock() m.lock.RLock()
defer m.lock.RUnlock() defer m.lock.RUnlock()
@@ -70,7 +70,7 @@ func (m *SafeMap) Get(key interface{}) (interface{}, bool) {
// Range calls f sequentially for each key and value present in the map. // Range calls f sequentially for each key and value present in the map.
// If f returns false, range stops the iteration. // If f returns false, range stops the iteration.
func (m *SafeMap) Range(f func(key, val interface{}) bool) { func (m *SafeMap) Range(f func(key, val any) bool) {
m.lock.RLock() m.lock.RLock()
defer m.lock.RUnlock() defer m.lock.RUnlock()
@@ -87,7 +87,7 @@ func (m *SafeMap) Range(f func(key, val interface{}) bool) {
} }
// Set sets the value into m with the given key. // Set sets the value into m with the given key.
func (m *SafeMap) Set(key, value interface{}) { func (m *SafeMap) Set(key, value any) {
m.lock.Lock() m.lock.Lock()
if m.deletionOld <= maxDeletion { if m.deletionOld <= maxDeletion {
if _, ok := m.dirtyNew[key]; ok { if _, ok := m.dirtyNew[key]; ok {

View File

@@ -138,7 +138,7 @@ func TestSafeMap_Range(t *testing.T) {
} }
var count int32 var count int32
m.Range(func(k, v interface{}) bool { m.Range(func(k, v any) bool {
atomic.AddInt32(&count, 1) atomic.AddInt32(&count, 1)
newMap.Set(k, v) newMap.Set(k, v)
return true return true

View File

@@ -17,14 +17,14 @@ const (
// Set is not thread-safe, for concurrent use, make sure to use it with synchronization. // Set is not thread-safe, for concurrent use, make sure to use it with synchronization.
type Set struct { type Set struct {
data map[interface{}]lang.PlaceholderType data map[any]lang.PlaceholderType
tp int tp int
} }
// NewSet returns a managed Set, can only put the values with the same type. // NewSet returns a managed Set, can only put the values with the same type.
func NewSet() *Set { func NewSet() *Set {
return &Set{ return &Set{
data: make(map[interface{}]lang.PlaceholderType), data: make(map[any]lang.PlaceholderType),
tp: untyped, tp: untyped,
} }
} }
@@ -32,13 +32,13 @@ func NewSet() *Set {
// NewUnmanagedSet returns an unmanaged Set, which can put values with different types. // NewUnmanagedSet returns an unmanaged Set, which can put values with different types.
func NewUnmanagedSet() *Set { func NewUnmanagedSet() *Set {
return &Set{ return &Set{
data: make(map[interface{}]lang.PlaceholderType), data: make(map[any]lang.PlaceholderType),
tp: unmanaged, tp: unmanaged,
} }
} }
// Add adds i into s. // Add adds i into s.
func (s *Set) Add(i ...interface{}) { func (s *Set) Add(i ...any) {
for _, each := range i { for _, each := range i {
s.add(each) s.add(each)
} }
@@ -80,7 +80,7 @@ func (s *Set) AddStr(ss ...string) {
} }
// Contains checks if i is in s. // Contains checks if i is in s.
func (s *Set) Contains(i interface{}) bool { func (s *Set) Contains(i any) bool {
if len(s.data) == 0 { if len(s.data) == 0 {
return false return false
} }
@@ -91,8 +91,8 @@ func (s *Set) Contains(i interface{}) bool {
} }
// Keys returns the keys in s. // Keys returns the keys in s.
func (s *Set) Keys() []interface{} { func (s *Set) Keys() []any {
var keys []interface{} var keys []any
for key := range s.data { for key := range s.data {
keys = append(keys, key) keys = append(keys, key)
@@ -167,7 +167,7 @@ func (s *Set) KeysStr() []string {
} }
// Remove removes i from s. // Remove removes i from s.
func (s *Set) Remove(i interface{}) { func (s *Set) Remove(i any) {
s.validate(i) s.validate(i)
delete(s.data, i) delete(s.data, i)
} }
@@ -177,7 +177,7 @@ func (s *Set) Count() int {
return len(s.data) return len(s.data)
} }
func (s *Set) add(i interface{}) { func (s *Set) add(i any) {
switch s.tp { switch s.tp {
case unmanaged: case unmanaged:
// do nothing // do nothing
@@ -189,7 +189,7 @@ func (s *Set) add(i interface{}) {
s.data[i] = lang.Placeholder s.data[i] = lang.Placeholder
} }
func (s *Set) setType(i interface{}) { func (s *Set) setType(i any) {
// s.tp can only be untyped here // s.tp can only be untyped here
switch i.(type) { switch i.(type) {
case int: case int:
@@ -205,7 +205,7 @@ func (s *Set) setType(i interface{}) {
} }
} }
func (s *Set) validate(i interface{}) { func (s *Set) validate(i any) {
if s.tp == unmanaged { if s.tp == unmanaged {
return return
} }
@@ -213,23 +213,23 @@ func (s *Set) validate(i interface{}) {
switch i.(type) { switch i.(type) {
case int: case int:
if s.tp != intType { if s.tp != intType {
logx.Errorf("Error: element is int, but set contains elements with type %d", s.tp) logx.Errorf("element is int, but set contains elements with type %d", s.tp)
} }
case int64: case int64:
if s.tp != int64Type { if s.tp != int64Type {
logx.Errorf("Error: element is int64, but set contains elements with type %d", s.tp) logx.Errorf("element is int64, but set contains elements with type %d", s.tp)
} }
case uint: case uint:
if s.tp != uintType { if s.tp != uintType {
logx.Errorf("Error: element is uint, but set contains elements with type %d", s.tp) logx.Errorf("element is uint, but set contains elements with type %d", s.tp)
} }
case uint64: case uint64:
if s.tp != uint64Type { if s.tp != uint64Type {
logx.Errorf("Error: element is uint64, but set contains elements with type %d", s.tp) logx.Errorf("element is uint64, but set contains elements with type %d", s.tp)
} }
case string: case string:
if s.tp != stringType { if s.tp != stringType {
logx.Errorf("Error: element is string, but set contains elements with type %d", s.tp) logx.Errorf("element is string, but set contains elements with type %d", s.tp)
} }
} }
} }

View File

@@ -13,7 +13,7 @@ func init() {
} }
func BenchmarkRawSet(b *testing.B) { func BenchmarkRawSet(b *testing.B) {
m := make(map[interface{}]struct{}) m := make(map[any]struct{})
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
m[i] = struct{}{} m[i] = struct{}{}
_ = m[i] _ = m[i]
@@ -39,7 +39,7 @@ func BenchmarkSet(b *testing.B) {
func TestAdd(t *testing.T) { func TestAdd(t *testing.T) {
// given // given
set := NewUnmanagedSet() set := NewUnmanagedSet()
values := []interface{}{1, 2, 3} values := []any{1, 2, 3}
// when // when
set.Add(values...) set.Add(values...)
@@ -135,7 +135,7 @@ func TestContainsUnmanagedWithoutElements(t *testing.T) {
func TestRemove(t *testing.T) { func TestRemove(t *testing.T) {
// given // given
set := NewSet() set := NewSet()
set.Add([]interface{}{1, 2, 3}...) set.Add([]any{1, 2, 3}...)
// when // when
set.Remove(2) set.Remove(2)
@@ -147,7 +147,7 @@ func TestRemove(t *testing.T) {
func TestCount(t *testing.T) { func TestCount(t *testing.T) {
// given // given
set := NewSet() set := NewSet()
set.Add([]interface{}{1, 2, 3}...) set.Add([]any{1, 2, 3}...)
// then // then
assert.Equal(t, set.Count(), 3) assert.Equal(t, set.Count(), 3)
@@ -198,5 +198,5 @@ func TestSetType(t *testing.T) {
set.add(1) set.add(1)
set.add("2") set.add("2")
vals := set.Keys() vals := set.Keys()
assert.ElementsMatch(t, []interface{}{1, "2"}, vals) assert.ElementsMatch(t, []any{1, "2"}, vals)
} }

View File

@@ -20,7 +20,7 @@ var (
type ( type (
// Execute defines the method to execute the task. // Execute defines the method to execute the task.
Execute func(key, value interface{}) Execute func(key, value any)
// A TimingWheel is a timing wheel object to schedule tasks. // A TimingWheel is a timing wheel object to schedule tasks.
TimingWheel struct { TimingWheel struct {
@@ -33,14 +33,14 @@ type (
execute Execute execute Execute
setChannel chan timingEntry setChannel chan timingEntry
moveChannel chan baseEntry moveChannel chan baseEntry
removeChannel chan interface{} removeChannel chan any
drainChannel chan func(key, value interface{}) drainChannel chan func(key, value any)
stopChannel chan lang.PlaceholderType stopChannel chan lang.PlaceholderType
} }
timingEntry struct { timingEntry struct {
baseEntry baseEntry
value interface{} value any
circle int circle int
diff int diff int
removed bool removed bool
@@ -48,7 +48,7 @@ type (
baseEntry struct { baseEntry struct {
delay time.Duration delay time.Duration
key interface{} key any
} }
positionEntry struct { positionEntry struct {
@@ -57,8 +57,8 @@ type (
} }
timingTask struct { timingTask struct {
key interface{} key any
value interface{} value any
} }
) )
@@ -85,8 +85,8 @@ func NewTimingWheelWithTicker(interval time.Duration, numSlots int, execute Exec
numSlots: numSlots, numSlots: numSlots,
setChannel: make(chan timingEntry), setChannel: make(chan timingEntry),
moveChannel: make(chan baseEntry), moveChannel: make(chan baseEntry),
removeChannel: make(chan interface{}), removeChannel: make(chan any),
drainChannel: make(chan func(key, value interface{})), drainChannel: make(chan func(key, value any)),
stopChannel: make(chan lang.PlaceholderType), stopChannel: make(chan lang.PlaceholderType),
} }
@@ -97,7 +97,7 @@ func NewTimingWheelWithTicker(interval time.Duration, numSlots int, execute Exec
} }
// Drain drains all items and executes them. // Drain drains all items and executes them.
func (tw *TimingWheel) Drain(fn func(key, value interface{})) error { func (tw *TimingWheel) Drain(fn func(key, value any)) error {
select { select {
case tw.drainChannel <- fn: case tw.drainChannel <- fn:
return nil return nil
@@ -107,7 +107,7 @@ func (tw *TimingWheel) Drain(fn func(key, value interface{})) error {
} }
// MoveTimer moves the task with the given key to the given delay. // MoveTimer moves the task with the given key to the given delay.
func (tw *TimingWheel) MoveTimer(key interface{}, delay time.Duration) error { func (tw *TimingWheel) MoveTimer(key any, delay time.Duration) error {
if delay <= 0 || key == nil { if delay <= 0 || key == nil {
return ErrArgument return ErrArgument
} }
@@ -124,7 +124,7 @@ func (tw *TimingWheel) MoveTimer(key interface{}, delay time.Duration) error {
} }
// RemoveTimer removes the task with the given key. // RemoveTimer removes the task with the given key.
func (tw *TimingWheel) RemoveTimer(key interface{}) error { func (tw *TimingWheel) RemoveTimer(key any) error {
if key == nil { if key == nil {
return ErrArgument return ErrArgument
} }
@@ -138,7 +138,7 @@ func (tw *TimingWheel) RemoveTimer(key interface{}) error {
} }
// SetTimer sets the task value with the given key to the delay. // SetTimer sets the task value with the given key to the delay.
func (tw *TimingWheel) SetTimer(key, value interface{}, delay time.Duration) error { func (tw *TimingWheel) SetTimer(key, value any, delay time.Duration) error {
if delay <= 0 || key == nil { if delay <= 0 || key == nil {
return ErrArgument return ErrArgument
} }
@@ -162,7 +162,7 @@ func (tw *TimingWheel) Stop() {
close(tw.stopChannel) close(tw.stopChannel)
} }
func (tw *TimingWheel) drainAll(fn func(key, value interface{})) { func (tw *TimingWheel) drainAll(fn func(key, value any)) {
runner := threading.NewTaskRunner(drainWorkers) runner := threading.NewTaskRunner(drainWorkers)
for _, slot := range tw.slots { for _, slot := range tw.slots {
for e := slot.Front(); e != nil; { for e := slot.Front(); e != nil; {
@@ -232,7 +232,7 @@ func (tw *TimingWheel) onTick() {
tw.scanAndRunTasks(l) tw.scanAndRunTasks(l)
} }
func (tw *TimingWheel) removeTask(key interface{}) { func (tw *TimingWheel) removeTask(key any) {
val, ok := tw.timers.Get(key) val, ok := tw.timers.Get(key)
if !ok { if !ok {
return return

View File

@@ -20,13 +20,13 @@ const (
) )
func TestNewTimingWheel(t *testing.T) { func TestNewTimingWheel(t *testing.T) {
_, err := NewTimingWheel(0, 10, func(key, value interface{}) {}) _, err := NewTimingWheel(0, 10, func(key, value any) {})
assert.NotNil(t, err) assert.NotNil(t, err)
} }
func TestTimingWheel_Drain(t *testing.T) { func TestTimingWheel_Drain(t *testing.T) {
ticker := timex.NewFakeTicker() ticker := timex.NewFakeTicker()
tw, _ := NewTimingWheelWithTicker(testStep, 10, func(k, v interface{}) { tw, _ := NewTimingWheelWithTicker(testStep, 10, func(k, v any) {
}, ticker) }, ticker)
tw.SetTimer("first", 3, testStep*4) tw.SetTimer("first", 3, testStep*4)
tw.SetTimer("second", 5, testStep*7) tw.SetTimer("second", 5, testStep*7)
@@ -36,7 +36,7 @@ func TestTimingWheel_Drain(t *testing.T) {
var lock sync.Mutex var lock sync.Mutex
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(3) wg.Add(3)
tw.Drain(func(key, value interface{}) { tw.Drain(func(key, value any) {
lock.Lock() lock.Lock()
defer lock.Unlock() defer lock.Unlock()
keys = append(keys, key.(string)) keys = append(keys, key.(string))
@@ -50,19 +50,19 @@ func TestTimingWheel_Drain(t *testing.T) {
assert.EqualValues(t, []string{"first", "second", "third"}, keys) assert.EqualValues(t, []string{"first", "second", "third"}, keys)
assert.EqualValues(t, []int{3, 5, 7}, vals) assert.EqualValues(t, []int{3, 5, 7}, vals)
var count int var count int
tw.Drain(func(key, value interface{}) { tw.Drain(func(key, value any) {
count++ count++
}) })
time.Sleep(time.Millisecond * 100) time.Sleep(time.Millisecond * 100)
assert.Equal(t, 0, count) assert.Equal(t, 0, count)
tw.Stop() tw.Stop()
assert.Equal(t, ErrClosed, tw.Drain(func(key, value interface{}) {})) assert.Equal(t, ErrClosed, tw.Drain(func(key, value any) {}))
} }
func TestTimingWheel_SetTimerSoon(t *testing.T) { func TestTimingWheel_SetTimerSoon(t *testing.T) {
run := syncx.NewAtomicBool() run := syncx.NewAtomicBool()
ticker := timex.NewFakeTicker() ticker := timex.NewFakeTicker()
tw, _ := NewTimingWheelWithTicker(testStep, 10, func(k, v interface{}) { tw, _ := NewTimingWheelWithTicker(testStep, 10, func(k, v any) {
assert.True(t, run.CompareAndSwap(false, true)) assert.True(t, run.CompareAndSwap(false, true))
assert.Equal(t, "any", k) assert.Equal(t, "any", k)
assert.Equal(t, 3, v.(int)) assert.Equal(t, 3, v.(int))
@@ -78,7 +78,7 @@ func TestTimingWheel_SetTimerSoon(t *testing.T) {
func TestTimingWheel_SetTimerTwice(t *testing.T) { func TestTimingWheel_SetTimerTwice(t *testing.T) {
run := syncx.NewAtomicBool() run := syncx.NewAtomicBool()
ticker := timex.NewFakeTicker() ticker := timex.NewFakeTicker()
tw, _ := NewTimingWheelWithTicker(testStep, 10, func(k, v interface{}) { tw, _ := NewTimingWheelWithTicker(testStep, 10, func(k, v any) {
assert.True(t, run.CompareAndSwap(false, true)) assert.True(t, run.CompareAndSwap(false, true))
assert.Equal(t, "any", k) assert.Equal(t, "any", k)
assert.Equal(t, 5, v.(int)) assert.Equal(t, 5, v.(int))
@@ -96,7 +96,7 @@ func TestTimingWheel_SetTimerTwice(t *testing.T) {
func TestTimingWheel_SetTimerWrongDelay(t *testing.T) { func TestTimingWheel_SetTimerWrongDelay(t *testing.T) {
ticker := timex.NewFakeTicker() ticker := timex.NewFakeTicker()
tw, _ := NewTimingWheelWithTicker(testStep, 10, func(k, v interface{}) {}, ticker) tw, _ := NewTimingWheelWithTicker(testStep, 10, func(k, v any) {}, ticker)
defer tw.Stop() defer tw.Stop()
assert.NotPanics(t, func() { assert.NotPanics(t, func() {
tw.SetTimer("any", 3, -testStep) tw.SetTimer("any", 3, -testStep)
@@ -105,7 +105,7 @@ func TestTimingWheel_SetTimerWrongDelay(t *testing.T) {
func TestTimingWheel_SetTimerAfterClose(t *testing.T) { func TestTimingWheel_SetTimerAfterClose(t *testing.T) {
ticker := timex.NewFakeTicker() ticker := timex.NewFakeTicker()
tw, _ := NewTimingWheelWithTicker(testStep, 10, func(k, v interface{}) {}, ticker) tw, _ := NewTimingWheelWithTicker(testStep, 10, func(k, v any) {}, ticker)
tw.Stop() tw.Stop()
assert.Equal(t, ErrClosed, tw.SetTimer("any", 3, testStep)) assert.Equal(t, ErrClosed, tw.SetTimer("any", 3, testStep))
} }
@@ -113,7 +113,7 @@ func TestTimingWheel_SetTimerAfterClose(t *testing.T) {
func TestTimingWheel_MoveTimer(t *testing.T) { func TestTimingWheel_MoveTimer(t *testing.T) {
run := syncx.NewAtomicBool() run := syncx.NewAtomicBool()
ticker := timex.NewFakeTicker() ticker := timex.NewFakeTicker()
tw, _ := NewTimingWheelWithTicker(testStep, 3, func(k, v interface{}) { tw, _ := NewTimingWheelWithTicker(testStep, 3, func(k, v any) {
assert.True(t, run.CompareAndSwap(false, true)) assert.True(t, run.CompareAndSwap(false, true))
assert.Equal(t, "any", k) assert.Equal(t, "any", k)
assert.Equal(t, 3, v.(int)) assert.Equal(t, 3, v.(int))
@@ -139,7 +139,7 @@ func TestTimingWheel_MoveTimer(t *testing.T) {
func TestTimingWheel_MoveTimerSoon(t *testing.T) { func TestTimingWheel_MoveTimerSoon(t *testing.T) {
run := syncx.NewAtomicBool() run := syncx.NewAtomicBool()
ticker := timex.NewFakeTicker() ticker := timex.NewFakeTicker()
tw, _ := NewTimingWheelWithTicker(testStep, 3, func(k, v interface{}) { tw, _ := NewTimingWheelWithTicker(testStep, 3, func(k, v any) {
assert.True(t, run.CompareAndSwap(false, true)) assert.True(t, run.CompareAndSwap(false, true))
assert.Equal(t, "any", k) assert.Equal(t, "any", k)
assert.Equal(t, 3, v.(int)) assert.Equal(t, 3, v.(int))
@@ -155,7 +155,7 @@ func TestTimingWheel_MoveTimerSoon(t *testing.T) {
func TestTimingWheel_MoveTimerEarlier(t *testing.T) { func TestTimingWheel_MoveTimerEarlier(t *testing.T) {
run := syncx.NewAtomicBool() run := syncx.NewAtomicBool()
ticker := timex.NewFakeTicker() ticker := timex.NewFakeTicker()
tw, _ := NewTimingWheelWithTicker(testStep, 10, func(k, v interface{}) { tw, _ := NewTimingWheelWithTicker(testStep, 10, func(k, v any) {
assert.True(t, run.CompareAndSwap(false, true)) assert.True(t, run.CompareAndSwap(false, true))
assert.Equal(t, "any", k) assert.Equal(t, "any", k)
assert.Equal(t, 3, v.(int)) assert.Equal(t, 3, v.(int))
@@ -173,7 +173,7 @@ func TestTimingWheel_MoveTimerEarlier(t *testing.T) {
func TestTimingWheel_RemoveTimer(t *testing.T) { func TestTimingWheel_RemoveTimer(t *testing.T) {
ticker := timex.NewFakeTicker() ticker := timex.NewFakeTicker()
tw, _ := NewTimingWheelWithTicker(testStep, 10, func(k, v interface{}) {}, ticker) tw, _ := NewTimingWheelWithTicker(testStep, 10, func(k, v any) {}, ticker)
tw.SetTimer("any", 3, testStep) tw.SetTimer("any", 3, testStep)
assert.NotPanics(t, func() { assert.NotPanics(t, func() {
tw.RemoveTimer("any") tw.RemoveTimer("any")
@@ -236,7 +236,7 @@ func TestTimingWheel_SetTimer(t *testing.T) {
} }
var actual int32 var actual int32
done := make(chan lang.PlaceholderType) done := make(chan lang.PlaceholderType)
tw, err := NewTimingWheelWithTicker(testStep, test.slots, func(key, value interface{}) { tw, err := NewTimingWheelWithTicker(testStep, test.slots, func(key, value any) {
assert.Equal(t, 1, key.(int)) assert.Equal(t, 1, key.(int))
assert.Equal(t, 2, value.(int)) assert.Equal(t, 2, value.(int))
actual = atomic.LoadInt32(&count) actual = atomic.LoadInt32(&count)
@@ -317,7 +317,7 @@ func TestTimingWheel_SetAndMoveThenStart(t *testing.T) {
} }
var actual int32 var actual int32
done := make(chan lang.PlaceholderType) done := make(chan lang.PlaceholderType)
tw, err := NewTimingWheelWithTicker(testStep, test.slots, func(key, value interface{}) { tw, err := NewTimingWheelWithTicker(testStep, test.slots, func(key, value any) {
actual = atomic.LoadInt32(&count) actual = atomic.LoadInt32(&count)
close(done) close(done)
}, ticker) }, ticker)
@@ -405,7 +405,7 @@ func TestTimingWheel_SetAndMoveTwice(t *testing.T) {
} }
var actual int32 var actual int32
done := make(chan lang.PlaceholderType) done := make(chan lang.PlaceholderType)
tw, err := NewTimingWheelWithTicker(testStep, test.slots, func(key, value interface{}) { tw, err := NewTimingWheelWithTicker(testStep, test.slots, func(key, value any) {
actual = atomic.LoadInt32(&count) actual = atomic.LoadInt32(&count)
close(done) close(done)
}, ticker) }, ticker)
@@ -486,7 +486,7 @@ func TestTimingWheel_ElapsedAndSet(t *testing.T) {
} }
var actual int32 var actual int32
done := make(chan lang.PlaceholderType) done := make(chan lang.PlaceholderType)
tw, err := NewTimingWheelWithTicker(testStep, test.slots, func(key, value interface{}) { tw, err := NewTimingWheelWithTicker(testStep, test.slots, func(key, value any) {
actual = atomic.LoadInt32(&count) actual = atomic.LoadInt32(&count)
close(done) close(done)
}, ticker) }, ticker)
@@ -577,7 +577,7 @@ func TestTimingWheel_ElapsedAndSetThenMove(t *testing.T) {
} }
var actual int32 var actual int32
done := make(chan lang.PlaceholderType) done := make(chan lang.PlaceholderType)
tw, err := NewTimingWheelWithTicker(testStep, test.slots, func(key, value interface{}) { tw, err := NewTimingWheelWithTicker(testStep, test.slots, func(key, value any) {
actual = atomic.LoadInt32(&count) actual = atomic.LoadInt32(&count)
close(done) close(done)
}, ticker) }, ticker)
@@ -612,7 +612,7 @@ func TestMoveAndRemoveTask(t *testing.T) {
} }
} }
var keys []int var keys []int
tw, _ := NewTimingWheelWithTicker(testStep, 10, func(k, v interface{}) { tw, _ := NewTimingWheelWithTicker(testStep, 10, func(k, v any) {
assert.Equal(t, "any", k) assert.Equal(t, "any", k)
assert.Equal(t, 3, v.(int)) assert.Equal(t, 3, v.(int))
keys = append(keys, v.(int)) keys = append(keys, v.(int))
@@ -632,7 +632,7 @@ func TestMoveAndRemoveTask(t *testing.T) {
func BenchmarkTimingWheel(b *testing.B) { func BenchmarkTimingWheel(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
tw, _ := NewTimingWheel(time.Second, 100, func(k, v interface{}) {}) tw, _ := NewTimingWheel(time.Second, 100, func(k, v any) {})
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
tw.SetTimer(i, i, time.Second) tw.SetTimer(i, i, time.Second)
tw.SetTimer(b.N+i, b.N+i, time.Second) tw.SetTimer(b.N+i, b.N+i, time.Second)

View File

@@ -13,21 +13,33 @@ import (
"github.com/zeromicro/go-zero/internal/encoding" "github.com/zeromicro/go-zero/internal/encoding"
) )
var loaders = map[string]func([]byte, interface{}) error{ const jsonTagKey = "json"
".json": LoadFromJsonBytes,
".toml": LoadFromTomlBytes, var (
".yaml": LoadFromYamlBytes, fillDefaultUnmarshaler = mapping.NewUnmarshaler(jsonTagKey, mapping.WithDefault())
".yml": LoadFromYamlBytes, loaders = map[string]func([]byte, any) error{
".json": LoadFromJsonBytes,
".toml": LoadFromTomlBytes,
".yaml": LoadFromYamlBytes,
".yml": LoadFromYamlBytes,
}
)
// children and mapField should not be both filled.
// named fields and map cannot be bound to the same field name.
type fieldInfo struct {
children map[string]*fieldInfo
mapField *fieldInfo
} }
type fieldInfo struct { // FillDefault fills the default values for the given v,
name string // and the premise is that the value of v must be guaranteed to be empty.
kind reflect.Kind func FillDefault(v any) error {
children map[string]fieldInfo return fillDefaultUnmarshaler.Unmarshal(map[string]any{}, v)
} }
// Load loads config into v from file, .json, .yaml and .yml are acceptable. // Load loads config into v from file, .json, .yaml and .yml are acceptable.
func Load(file string, v interface{}, opts ...Option) error { func Load(file string, v any, opts ...Option) error {
content, err := os.ReadFile(file) content, err := os.ReadFile(file)
if err != nil { if err != nil {
return err return err
@@ -52,31 +64,35 @@ func Load(file string, v interface{}, opts ...Option) error {
// LoadConfig loads config into v from file, .json, .yaml and .yml are acceptable. // LoadConfig loads config into v from file, .json, .yaml and .yml are acceptable.
// Deprecated: use Load instead. // Deprecated: use Load instead.
func LoadConfig(file string, v interface{}, opts ...Option) error { func LoadConfig(file string, v any, opts ...Option) error {
return Load(file, v, opts...) return Load(file, v, opts...)
} }
// LoadFromJsonBytes loads config into v from content json bytes. // LoadFromJsonBytes loads config into v from content json bytes.
func LoadFromJsonBytes(content []byte, v interface{}) error { func LoadFromJsonBytes(content []byte, v any) error {
var m map[string]interface{} info, err := buildFieldsInfo(reflect.TypeOf(v))
if err != nil {
return err
}
var m map[string]any
if err := jsonx.Unmarshal(content, &m); err != nil { if err := jsonx.Unmarshal(content, &m); err != nil {
return err return err
} }
finfo := buildFieldsInfo(reflect.TypeOf(v)) lowerCaseKeyMap := toLowerCaseKeyMap(m, info)
lowerCaseKeyMap := toLowerCaseKeyMap(m, finfo)
return mapping.UnmarshalJsonMap(lowerCaseKeyMap, v, mapping.WithCanonicalKeyFunc(toLowerCase)) return mapping.UnmarshalJsonMap(lowerCaseKeyMap, v, mapping.WithCanonicalKeyFunc(toLowerCase))
} }
// LoadConfigFromJsonBytes loads config into v from content json bytes. // LoadConfigFromJsonBytes loads config into v from content json bytes.
// Deprecated: use LoadFromJsonBytes instead. // Deprecated: use LoadFromJsonBytes instead.
func LoadConfigFromJsonBytes(content []byte, v interface{}) error { func LoadConfigFromJsonBytes(content []byte, v any) error {
return LoadFromJsonBytes(content, v) return LoadFromJsonBytes(content, v)
} }
// LoadFromTomlBytes loads config into v from content toml bytes. // LoadFromTomlBytes loads config into v from content toml bytes.
func LoadFromTomlBytes(content []byte, v interface{}) error { func LoadFromTomlBytes(content []byte, v any) error {
b, err := encoding.TomlToJson(content) b, err := encoding.TomlToJson(content)
if err != nil { if err != nil {
return err return err
@@ -86,7 +102,7 @@ func LoadFromTomlBytes(content []byte, v interface{}) error {
} }
// LoadFromYamlBytes loads config into v from content yaml bytes. // LoadFromYamlBytes loads config into v from content yaml bytes.
func LoadFromYamlBytes(content []byte, v interface{}) error { func LoadFromYamlBytes(content []byte, v any) error {
b, err := encoding.YamlToJson(content) b, err := encoding.YamlToJson(content)
if err != nil { if err != nil {
return err return err
@@ -97,18 +113,74 @@ func LoadFromYamlBytes(content []byte, v interface{}) error {
// LoadConfigFromYamlBytes loads config into v from content yaml bytes. // LoadConfigFromYamlBytes loads config into v from content yaml bytes.
// Deprecated: use LoadFromYamlBytes instead. // Deprecated: use LoadFromYamlBytes instead.
func LoadConfigFromYamlBytes(content []byte, v interface{}) error { func LoadConfigFromYamlBytes(content []byte, v any) error {
return LoadFromYamlBytes(content, v) return LoadFromYamlBytes(content, v)
} }
// MustLoad loads config into v from path, exits on error. // MustLoad loads config into v from path, exits on error.
func MustLoad(path string, v interface{}, opts ...Option) { func MustLoad(path string, v any, opts ...Option) {
if err := Load(path, v, opts...); err != nil { if err := Load(path, v, opts...); err != nil {
log.Fatalf("error: config file %s, %s", path, err.Error()) log.Fatalf("error: config file %s, %s", path, err.Error())
} }
} }
func buildFieldsInfo(tp reflect.Type) map[string]fieldInfo { func addOrMergeFields(info *fieldInfo, key string, child *fieldInfo) error {
if prev, ok := info.children[key]; ok {
if child.mapField != nil {
return newDupKeyError(key)
}
if err := mergeFields(prev, key, child.children); err != nil {
return err
}
} else {
info.children[key] = child
}
return nil
}
func buildAnonymousFieldInfo(info *fieldInfo, lowerCaseName string, ft reflect.Type) error {
switch ft.Kind() {
case reflect.Struct:
fields, err := buildFieldsInfo(ft)
if err != nil {
return err
}
for k, v := range fields.children {
if err = addOrMergeFields(info, k, v); err != nil {
return err
}
}
case reflect.Map:
elemField, err := buildFieldsInfo(mapping.Deref(ft.Elem()))
if err != nil {
return err
}
if _, ok := info.children[lowerCaseName]; ok {
return newDupKeyError(lowerCaseName)
}
info.children[lowerCaseName] = &fieldInfo{
children: make(map[string]*fieldInfo),
mapField: elemField,
}
default:
if _, ok := info.children[lowerCaseName]; ok {
return newDupKeyError(lowerCaseName)
}
info.children[lowerCaseName] = &fieldInfo{
children: make(map[string]*fieldInfo),
}
}
return nil
}
func buildFieldsInfo(tp reflect.Type) (*fieldInfo, error) {
tp = mapping.Deref(tp) tp = mapping.Deref(tp)
switch tp.Kind() { switch tp.Kind() {
@@ -116,66 +188,100 @@ func buildFieldsInfo(tp reflect.Type) map[string]fieldInfo {
return buildStructFieldsInfo(tp) return buildStructFieldsInfo(tp)
case reflect.Array, reflect.Slice: case reflect.Array, reflect.Slice:
return buildFieldsInfo(mapping.Deref(tp.Elem())) return buildFieldsInfo(mapping.Deref(tp.Elem()))
case reflect.Chan, reflect.Func:
return nil, fmt.Errorf("unsupported type: %s", tp.Kind())
default: default:
return nil return &fieldInfo{
children: make(map[string]*fieldInfo),
}, nil
} }
} }
func buildStructFieldsInfo(tp reflect.Type) map[string]fieldInfo { func buildNamedFieldInfo(info *fieldInfo, lowerCaseName string, ft reflect.Type) error {
info := make(map[string]fieldInfo) var finfo *fieldInfo
var err error
switch ft.Kind() {
case reflect.Struct:
finfo, err = buildFieldsInfo(ft)
if err != nil {
return err
}
case reflect.Array, reflect.Slice:
finfo, err = buildFieldsInfo(ft.Elem())
if err != nil {
return err
}
case reflect.Map:
elemInfo, err := buildFieldsInfo(mapping.Deref(ft.Elem()))
if err != nil {
return err
}
finfo = &fieldInfo{
children: make(map[string]*fieldInfo),
mapField: elemInfo,
}
default:
finfo, err = buildFieldsInfo(ft)
if err != nil {
return err
}
}
return addOrMergeFields(info, lowerCaseName, finfo)
}
func buildStructFieldsInfo(tp reflect.Type) (*fieldInfo, error) {
info := &fieldInfo{
children: make(map[string]*fieldInfo),
}
for i := 0; i < tp.NumField(); i++ { for i := 0; i < tp.NumField(); i++ {
field := tp.Field(i) field := tp.Field(i)
name := field.Name name := field.Name
lowerCaseName := toLowerCase(name) lowerCaseName := toLowerCase(name)
ft := mapping.Deref(field.Type) ft := mapping.Deref(field.Type)
// flatten anonymous fields // flatten anonymous fields
if field.Anonymous { if field.Anonymous {
if ft.Kind() == reflect.Struct { if err := buildAnonymousFieldInfo(info, lowerCaseName, ft); err != nil {
fields := buildFieldsInfo(ft) return nil, err
for k, v := range fields {
info[k] = v
}
} else {
info[lowerCaseName] = fieldInfo{
name: name,
kind: ft.Kind(),
}
} }
continue } else if err := buildNamedFieldInfo(info, lowerCaseName, ft); err != nil {
} return nil, err
var fields map[string]fieldInfo
switch ft.Kind() {
case reflect.Struct:
fields = buildFieldsInfo(ft)
case reflect.Array, reflect.Slice:
fields = buildFieldsInfo(ft.Elem())
case reflect.Map:
fields = buildFieldsInfo(ft.Elem())
}
info[lowerCaseName] = fieldInfo{
name: name,
kind: ft.Kind(),
children: fields,
} }
} }
return info return info, nil
}
func mergeFields(prev *fieldInfo, key string, children map[string]*fieldInfo) error {
if len(prev.children) == 0 || len(children) == 0 {
return newDupKeyError(key)
}
// merge fields
for k, v := range children {
if _, ok := prev.children[k]; ok {
return newDupKeyError(k)
}
prev.children[k] = v
}
return nil
} }
func toLowerCase(s string) string { func toLowerCase(s string) string {
return strings.ToLower(s) return strings.ToLower(s)
} }
func toLowerCaseInterface(v interface{}, info map[string]fieldInfo) interface{} { func toLowerCaseInterface(v any, info *fieldInfo) any {
switch vv := v.(type) { switch vv := v.(type) {
case map[string]interface{}: case map[string]any:
return toLowerCaseKeyMap(vv, info) return toLowerCaseKeyMap(vv, info)
case []interface{}: case []any:
var arr []interface{} var arr []any
for _, vvv := range vv { for _, vvv := range vv {
arr = append(arr, toLowerCaseInterface(vvv, info)) arr = append(arr, toLowerCaseInterface(vvv, info))
} }
@@ -185,19 +291,21 @@ func toLowerCaseInterface(v interface{}, info map[string]fieldInfo) interface{}
} }
} }
func toLowerCaseKeyMap(m map[string]interface{}, info map[string]fieldInfo) map[string]interface{} { func toLowerCaseKeyMap(m map[string]any, info *fieldInfo) map[string]any {
res := make(map[string]interface{}) res := make(map[string]any)
for k, v := range m { for k, v := range m {
ti, ok := info[k] ti, ok := info.children[k]
if ok { if ok {
res[k] = toLowerCaseInterface(v, ti.children) res[k] = toLowerCaseInterface(v, ti)
continue continue
} }
lk := toLowerCase(k) lk := toLowerCase(k)
if ti, ok = info[lk]; ok { if ti, ok = info.children[lk]; ok {
res[lk] = toLowerCaseInterface(v, ti.children) res[lk] = toLowerCaseInterface(v, ti)
} else if info.mapField != nil {
res[k] = toLowerCaseInterface(v, info.mapField)
} else { } else {
res[k] = v res[k] = v
} }
@@ -205,3 +313,15 @@ func toLowerCaseKeyMap(m map[string]interface{}, info map[string]fieldInfo) map[
return res return res
} }
type dupKeyError struct {
key string
}
func newDupKeyError(key string) dupKeyError {
return dupKeyError{key: key}
}
func (e dupKeyError) Error() string {
return fmt.Sprintf("duplicated key %s", e.key)
}

View File

@@ -9,6 +9,8 @@ import (
"github.com/zeromicro/go-zero/core/hash" "github.com/zeromicro/go-zero/core/hash"
) )
var dupErr dupKeyError
func TestLoadConfig_notExists(t *testing.T) { func TestLoadConfig_notExists(t *testing.T) {
assert.NotNil(t, Load("not_a_file", nil)) assert.NotNil(t, Load("not_a_file", nil))
} }
@@ -17,7 +19,7 @@ func TestLoadConfig_notRecogFile(t *testing.T) {
filename, err := fs.TempFilenameWithText("hello") filename, err := fs.TempFilenameWithText("hello")
assert.Nil(t, err) assert.Nil(t, err)
defer os.Remove(filename) defer os.Remove(filename)
assert.NotNil(t, Load(filename, nil)) assert.NotNil(t, LoadConfig(filename, nil))
} }
func TestConfigJson(t *testing.T) { func TestConfigJson(t *testing.T) {
@@ -64,7 +66,7 @@ func TestLoadFromJsonBytesArray(t *testing.T) {
} }
} }
assert.NoError(t, LoadFromJsonBytes(input, &val)) assert.NoError(t, LoadConfigFromJsonBytes(input, &val))
var expect []string var expect []string
for _, user := range val.Users { for _, user := range val.Users {
expect = append(expect, user.Name) expect = append(expect, user.Name)
@@ -172,7 +174,7 @@ B: bar`)
A string A string
B string B string
} }
assert.NoError(t, LoadFromYamlBytes(text, &val1)) assert.NoError(t, LoadConfigFromYamlBytes(text, &val1))
assert.Equal(t, "foo", val1.A) assert.Equal(t, "foo", val1.A)
assert.Equal(t, "bar", val1.B) assert.Equal(t, "bar", val1.B)
assert.NoError(t, LoadFromYamlBytes(text, &val2)) assert.NoError(t, LoadFromYamlBytes(text, &val2))
@@ -384,6 +386,102 @@ func TestLoadFromYamlBytesLayers(t *testing.T) {
assert.Equal(t, "foo", val.Value) assert.Equal(t, "foo", val.Value)
} }
func TestLoadFromYamlItemOverlay(t *testing.T) {
type (
Redis struct {
Host string
Port int
}
RedisKey struct {
Redis
Key string
}
Server struct {
Redis RedisKey
}
TestConfig struct {
Server
Redis Redis
}
)
input := []byte(`Redis:
Host: localhost
Port: 6379
Key: test
`)
var c TestConfig
assert.ErrorAs(t, LoadFromYamlBytes(input, &c), &dupErr)
}
func TestLoadFromYamlItemOverlayReverse(t *testing.T) {
type (
Redis struct {
Host string
Port int
}
RedisKey struct {
Redis
Key string
}
Server struct {
Redis Redis
}
TestConfig struct {
Redis RedisKey
Server
}
)
input := []byte(`Redis:
Host: localhost
Port: 6379
Key: test
`)
var c TestConfig
assert.ErrorAs(t, LoadFromYamlBytes(input, &c), &dupErr)
}
func TestLoadFromYamlItemOverlayWithMap(t *testing.T) {
type (
Redis struct {
Host string
Port int
}
RedisKey struct {
Redis
Key string
}
Server struct {
Redis RedisKey
}
TestConfig struct {
Server
Redis map[string]interface{}
}
)
input := []byte(`Redis:
Host: localhost
Port: 6379
Key: test
`)
var c TestConfig
assert.ErrorAs(t, LoadFromYamlBytes(input, &c), &dupErr)
}
func TestUnmarshalJsonBytesMap(t *testing.T) { func TestUnmarshalJsonBytesMap(t *testing.T) {
input := []byte(`{"foo":{"/mtproto.RPCTos": "bff.bff","bar":"baz"}}`) input := []byte(`{"foo":{"/mtproto.RPCTos": "bff.bff","bar":"baz"}}`)
@@ -450,6 +548,480 @@ func TestUnmarshalJsonBytesWithAnonymousField(t *testing.T) {
assert.Equal(t, Int(3), c.Int) assert.Equal(t, Int(3), c.Int)
} }
func TestUnmarshalJsonBytesWithMapValueOfStruct(t *testing.T) {
type (
Value struct {
Name string
}
Config struct {
Items map[string]Value
}
)
var inputs = [][]byte{
[]byte(`{"Items": {"Key":{"Name": "foo"}}}`),
[]byte(`{"Items": {"Key":{"Name": "foo"}}}`),
[]byte(`{"items": {"key":{"name": "foo"}}}`),
[]byte(`{"items": {"key":{"name": "foo"}}}`),
}
for _, input := range inputs {
var c Config
if assert.NoError(t, LoadFromJsonBytes(input, &c)) {
assert.Equal(t, 1, len(c.Items))
for _, v := range c.Items {
assert.Equal(t, "foo", v.Name)
}
}
}
}
func TestUnmarshalJsonBytesWithMapTypeValueOfStruct(t *testing.T) {
type (
Value struct {
Name string
}
Map map[string]Value
Config struct {
Map
}
)
var inputs = [][]byte{
[]byte(`{"Map": {"Key":{"Name": "foo"}}}`),
[]byte(`{"Map": {"Key":{"Name": "foo"}}}`),
[]byte(`{"map": {"key":{"name": "foo"}}}`),
[]byte(`{"map": {"key":{"name": "foo"}}}`),
}
for _, input := range inputs {
var c Config
if assert.NoError(t, LoadFromJsonBytes(input, &c)) {
assert.Equal(t, 1, len(c.Map))
for _, v := range c.Map {
assert.Equal(t, "foo", v.Name)
}
}
}
}
func Test_FieldOverwrite(t *testing.T) {
t.Run("normal", func(t *testing.T) {
type Base struct {
Name string
}
type St1 struct {
Base
Name2 string
}
type St2 struct {
Base
Name2 string
}
type St3 struct {
*Base
Name2 string
}
type St4 struct {
*Base
Name2 *string
}
validate := func(val any) {
input := []byte(`{"Name": "hello", "Name2": "world"}`)
assert.NoError(t, LoadFromJsonBytes(input, val))
}
validate(&St1{})
validate(&St2{})
validate(&St3{})
validate(&St4{})
})
t.Run("Inherit Override", func(t *testing.T) {
type Base struct {
Name string
}
type St1 struct {
Base
Name string
}
type St2 struct {
Base
Name int
}
type St3 struct {
*Base
Name int
}
type St4 struct {
*Base
Name *string
}
validate := func(val any) {
input := []byte(`{"Name": "hello"}`)
err := LoadFromJsonBytes(input, val)
assert.ErrorAs(t, err, &dupErr)
assert.Equal(t, newDupKeyError("name").Error(), err.Error())
}
validate(&St1{})
validate(&St2{})
validate(&St3{})
validate(&St4{})
})
t.Run("Inherit more", func(t *testing.T) {
type Base1 struct {
Name string
}
type St0 struct {
Base1
Name string
}
type St1 struct {
St0
Name string
}
type St2 struct {
St0
Name int
}
type St3 struct {
*St0
Name int
}
type St4 struct {
*St0
Name *int
}
validate := func(val any) {
input := []byte(`{"Name": "hello"}`)
err := LoadFromJsonBytes(input, val)
assert.ErrorAs(t, err, &dupErr)
assert.Equal(t, newDupKeyError("name").Error(), err.Error())
}
validate(&St0{})
validate(&St1{})
validate(&St2{})
validate(&St3{})
validate(&St4{})
})
}
func TestFieldOverwriteComplicated(t *testing.T) {
t.Run("double maps", func(t *testing.T) {
type (
Base1 struct {
Values map[string]string
}
Base2 struct {
Values map[string]string
}
Config struct {
Base1
Base2
}
)
var c Config
input := []byte(`{"Values": {"Key": "Value"}}`)
assert.ErrorAs(t, LoadFromJsonBytes(input, &c), &dupErr)
})
t.Run("merge children", func(t *testing.T) {
type (
Inner1 struct {
Name string
}
Inner2 struct {
Age int
}
Base1 struct {
Inner Inner1
}
Base2 struct {
Inner Inner2
}
Config struct {
Base1
Base2
}
)
var c Config
input := []byte(`{"Inner": {"Name": "foo", "Age": 10}}`)
if assert.NoError(t, LoadFromJsonBytes(input, &c)) {
assert.Equal(t, "foo", c.Base1.Inner.Name)
assert.Equal(t, 10, c.Base2.Inner.Age)
}
})
t.Run("overwritten maps", func(t *testing.T) {
type (
Inner struct {
Map map[string]string
}
Config struct {
Map map[string]string
Inner
}
)
var c Config
input := []byte(`{"Inner": {"Map": {"Key": "Value"}}}`)
assert.ErrorAs(t, LoadFromJsonBytes(input, &c), &dupErr)
})
t.Run("overwritten nested maps", func(t *testing.T) {
type (
Inner struct {
Map map[string]string
}
Middle1 struct {
Map map[string]string
Inner
}
Middle2 struct {
Map map[string]string
Inner
}
Config struct {
Middle1
Middle2
}
)
var c Config
input := []byte(`{"Middle1": {"Inner": {"Map": {"Key": "Value"}}}}`)
assert.ErrorAs(t, LoadFromJsonBytes(input, &c), &dupErr)
})
t.Run("overwritten outer/inner maps", func(t *testing.T) {
type (
Inner struct {
Map map[string]string
}
Middle struct {
Inner
Map map[string]string
}
Config struct {
Middle
}
)
var c Config
input := []byte(`{"Middle": {"Inner": {"Map": {"Key": "Value"}}}}`)
assert.ErrorAs(t, LoadFromJsonBytes(input, &c), &dupErr)
})
t.Run("overwritten anonymous maps", func(t *testing.T) {
type (
Inner struct {
Map map[string]string
}
Middle struct {
Inner
Map map[string]string
}
Elem map[string]Middle
Config struct {
Elem
}
)
var c Config
input := []byte(`{"Elem": {"Key": {"Inner": {"Map": {"Key": "Value"}}}}}`)
assert.ErrorAs(t, LoadFromJsonBytes(input, &c), &dupErr)
})
t.Run("overwritten primitive and map", func(t *testing.T) {
type (
Inner struct {
Value string
}
Elem map[string]Inner
Named struct {
Elem string
}
Config struct {
Named
Elem
}
)
var c Config
input := []byte(`{"Elem": {"Key": {"Value": "Value"}}}`)
assert.ErrorAs(t, LoadFromJsonBytes(input, &c), &dupErr)
})
t.Run("overwritten map and slice", func(t *testing.T) {
type (
Inner struct {
Value string
}
Elem []Inner
Named struct {
Elem string
}
Config struct {
Named
Elem
}
)
var c Config
input := []byte(`{"Elem": {"Key": {"Value": "Value"}}}`)
assert.ErrorAs(t, LoadFromJsonBytes(input, &c), &dupErr)
})
t.Run("overwritten map and string", func(t *testing.T) {
type (
Elem string
Named struct {
Elem string
}
Config struct {
Named
Elem
}
)
var c Config
input := []byte(`{"Elem": {"Key": {"Value": "Value"}}}`)
assert.ErrorAs(t, LoadFromJsonBytes(input, &c), &dupErr)
})
}
func TestLoadNamedFieldOverwritten(t *testing.T) {
t.Run("overwritten named struct", func(t *testing.T) {
type (
Elem string
Named struct {
Elem string
}
Base struct {
Named
Elem
}
Config struct {
Val Base
}
)
var c Config
input := []byte(`{"Val": {"Elem": {"Key": {"Value": "Value"}}}}`)
assert.ErrorAs(t, LoadFromJsonBytes(input, &c), &dupErr)
})
t.Run("overwritten named []struct", func(t *testing.T) {
type (
Elem string
Named struct {
Elem string
}
Base struct {
Named
Elem
}
Config struct {
Vals []Base
}
)
var c Config
input := []byte(`{"Vals": [{"Elem": {"Key": {"Value": "Value"}}}]}`)
assert.ErrorAs(t, LoadFromJsonBytes(input, &c), &dupErr)
})
t.Run("overwritten named map[string]struct", func(t *testing.T) {
type (
Elem string
Named struct {
Elem string
}
Base struct {
Named
Elem
}
Config struct {
Vals map[string]Base
}
)
var c Config
input := []byte(`{"Vals": {"Key": {"Elem": {"Key": {"Value": "Value"}}}}}`)
assert.ErrorAs(t, LoadFromJsonBytes(input, &c), &dupErr)
})
t.Run("overwritten named *struct", func(t *testing.T) {
type (
Elem string
Named struct {
Elem string
}
Base struct {
Named
Elem
}
Config struct {
Vals *Base
}
)
var c Config
input := []byte(`{"Vals": [{"Elem": {"Key": {"Value": "Value"}}}]}`)
assert.ErrorAs(t, LoadFromJsonBytes(input, &c), &dupErr)
})
t.Run("overwritten named struct", func(t *testing.T) {
type (
Named struct {
Elem string
}
Base struct {
Named
Elem Named
}
Config struct {
Val Base
}
)
var c Config
input := []byte(`{"Val": {"Elem": "Value"}}`)
assert.ErrorAs(t, LoadFromJsonBytes(input, &c), &dupErr)
})
t.Run("overwritten named struct", func(t *testing.T) {
type Config struct {
Val chan int
}
var c Config
input := []byte(`{"Val": 1}`)
assert.Error(t, LoadFromJsonBytes(input, &c))
})
}
func createTempFile(ext, text string) (string, error) { func createTempFile(ext, text string) (string, error) {
tmpfile, err := os.CreateTemp(os.TempDir(), hash.Md5Hex([]byte(text))+"*"+ext) tmpfile, err := os.CreateTemp(os.TempDir(), hash.Md5Hex([]byte(text))+"*"+ext)
if err != nil { if err != nil {
@@ -467,3 +1039,55 @@ func createTempFile(ext, text string) (string, error) {
return filename, nil return filename, nil
} }
func TestFillDefaultUnmarshal(t *testing.T) {
t.Run("nil", func(t *testing.T) {
type St struct{}
err := FillDefault(St{})
assert.Error(t, err)
})
t.Run("not nil", func(t *testing.T) {
type St struct{}
err := FillDefault(&St{})
assert.NoError(t, err)
})
t.Run("default", func(t *testing.T) {
type St struct {
A string `json:",default=a"`
B string
}
var st St
err := FillDefault(&st)
assert.NoError(t, err)
assert.Equal(t, st.A, "a")
})
t.Run("env", func(t *testing.T) {
type St struct {
A string `json:",default=a"`
B string
C string `json:",env=TEST_C"`
}
t.Setenv("TEST_C", "c")
var st St
err := FillDefault(&st)
assert.NoError(t, err)
assert.Equal(t, st.A, "a")
assert.Equal(t, st.C, "c")
})
t.Run("has vaue", func(t *testing.T) {
type St struct {
A string `json:",default=a"`
B string
}
var st = St{
A: "b",
}
err := FillDefault(&st)
assert.Error(t, err)
})
}

View File

@@ -12,7 +12,6 @@ import (
// PropertyError represents a configuration error message. // PropertyError represents a configuration error message.
type PropertyError struct { type PropertyError struct {
error
message string message string
} }

View File

@@ -4,6 +4,7 @@
```go ```go
type RestfulConf struct { type RestfulConf struct {
ServiceName string `json:",env=SERVICE_NAME"` // read from env automatically
Host string `json:",default=0.0.0.0"` Host string `json:",default=0.0.0.0"`
Port int Port int
LogMode string `json:",options=[file,console]"` LogMode string `json:",options=[file,console]"`
@@ -21,20 +22,20 @@ type RestfulConf struct {
```yaml ```yaml
# most fields are optional or have default values # most fields are optional or have default values
Port: 8080 port: 8080
LogMode: console logMode: console
# you can use env settings # you can use env settings
MaxBytes: ${MAX_BYTES} maxBytes: ${MAX_BYTES}
``` ```
- toml example - toml example
```toml ```toml
# most fields are optional or have default values # most fields are optional or have default values
Port = 8_080 port = 8_080
LogMode = "console" logMode = "console"
# you can use env settings # you can use env settings
MaxBytes = "${MAX_BYTES}" maxBytes = "${MAX_BYTES}"
``` ```
3. Load the config from a file: 3. Load the config from a file:

View File

@@ -14,13 +14,13 @@ type contextValuer struct {
context.Context context.Context
} }
func (cv contextValuer) Value(key string) (interface{}, bool) { func (cv contextValuer) Value(key string) (any, bool) {
v := cv.Context.Value(key) v := cv.Context.Value(key)
return v, v != nil return v, v != nil
} }
// For unmarshals ctx into v. // For unmarshals ctx into v.
func For(ctx context.Context, v interface{}) error { func For(ctx context.Context, v any) error {
return unmarshaler.UnmarshalValuer(contextValuer{ return unmarshaler.UnmarshalValuer(contextValuer{
Context: ctx, Context: ctx,
}, v) }, v)

View File

@@ -81,7 +81,7 @@ func (mr *MockEtcdClientMockRecorder) Ctx() *gomock.Call {
// Get mocks base method // Get mocks base method
func (m *MockEtcdClient) Get(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) { func (m *MockEtcdClient) Get(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
varargs := []interface{}{ctx, key} varargs := []any{ctx, key}
for _, a := range opts { for _, a := range opts {
varargs = append(varargs, a) varargs = append(varargs, a)
} }
@@ -92,9 +92,9 @@ func (m *MockEtcdClient) Get(ctx context.Context, key string, opts ...clientv3.O
} }
// Get indicates an expected call of Get // Get indicates an expected call of Get
func (mr *MockEtcdClientMockRecorder) Get(ctx, key interface{}, opts ...interface{}) *gomock.Call { func (mr *MockEtcdClientMockRecorder) Get(ctx, key any, opts ...any) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{ctx, key}, opts...) varargs := append([]any{ctx, key}, opts...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockEtcdClient)(nil).Get), varargs...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockEtcdClient)(nil).Get), varargs...)
} }
@@ -108,7 +108,7 @@ func (m *MockEtcdClient) Grant(ctx context.Context, ttl int64) (*clientv3.LeaseG
} }
// Grant indicates an expected call of Grant // Grant indicates an expected call of Grant
func (mr *MockEtcdClientMockRecorder) Grant(ctx, ttl interface{}) *gomock.Call { func (mr *MockEtcdClientMockRecorder) Grant(ctx, ttl any) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Grant", reflect.TypeOf((*MockEtcdClient)(nil).Grant), ctx, ttl) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Grant", reflect.TypeOf((*MockEtcdClient)(nil).Grant), ctx, ttl)
} }
@@ -123,7 +123,7 @@ func (m *MockEtcdClient) KeepAlive(ctx context.Context, id clientv3.LeaseID) (<-
} }
// KeepAlive indicates an expected call of KeepAlive // KeepAlive indicates an expected call of KeepAlive
func (mr *MockEtcdClientMockRecorder) KeepAlive(ctx, id interface{}) *gomock.Call { func (mr *MockEtcdClientMockRecorder) KeepAlive(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KeepAlive", reflect.TypeOf((*MockEtcdClient)(nil).KeepAlive), ctx, id) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KeepAlive", reflect.TypeOf((*MockEtcdClient)(nil).KeepAlive), ctx, id)
} }
@@ -131,7 +131,7 @@ func (mr *MockEtcdClientMockRecorder) KeepAlive(ctx, id interface{}) *gomock.Cal
// Put mocks base method // Put mocks base method
func (m *MockEtcdClient) Put(ctx context.Context, key, val string, opts ...clientv3.OpOption) (*clientv3.PutResponse, error) { func (m *MockEtcdClient) Put(ctx context.Context, key, val string, opts ...clientv3.OpOption) (*clientv3.PutResponse, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
varargs := []interface{}{ctx, key, val} varargs := []any{ctx, key, val}
for _, a := range opts { for _, a := range opts {
varargs = append(varargs, a) varargs = append(varargs, a)
} }
@@ -142,9 +142,9 @@ func (m *MockEtcdClient) Put(ctx context.Context, key, val string, opts ...clien
} }
// Put indicates an expected call of Put // Put indicates an expected call of Put
func (mr *MockEtcdClientMockRecorder) Put(ctx, key, val interface{}, opts ...interface{}) *gomock.Call { func (mr *MockEtcdClientMockRecorder) Put(ctx, key, val any, opts ...any) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{ctx, key, val}, opts...) varargs := append([]any{ctx, key, val}, opts...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockEtcdClient)(nil).Put), varargs...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockEtcdClient)(nil).Put), varargs...)
} }
@@ -158,7 +158,7 @@ func (m *MockEtcdClient) Revoke(ctx context.Context, id clientv3.LeaseID) (*clie
} }
// Revoke indicates an expected call of Revoke // Revoke indicates an expected call of Revoke
func (mr *MockEtcdClientMockRecorder) Revoke(ctx, id interface{}) *gomock.Call { func (mr *MockEtcdClientMockRecorder) Revoke(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Revoke", reflect.TypeOf((*MockEtcdClient)(nil).Revoke), ctx, id) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Revoke", reflect.TypeOf((*MockEtcdClient)(nil).Revoke), ctx, id)
} }
@@ -166,7 +166,7 @@ func (mr *MockEtcdClientMockRecorder) Revoke(ctx, id interface{}) *gomock.Call {
// Watch mocks base method // Watch mocks base method
func (m *MockEtcdClient) Watch(ctx context.Context, key string, opts ...clientv3.OpOption) clientv3.WatchChan { func (m *MockEtcdClient) Watch(ctx context.Context, key string, opts ...clientv3.OpOption) clientv3.WatchChan {
m.ctrl.T.Helper() m.ctrl.T.Helper()
varargs := []interface{}{ctx, key} varargs := []any{ctx, key}
for _, a := range opts { for _, a := range opts {
varargs = append(varargs, a) varargs = append(varargs, a)
} }
@@ -176,8 +176,8 @@ func (m *MockEtcdClient) Watch(ctx context.Context, key string, opts ...clientv3
} }
// Watch indicates an expected call of Watch // Watch indicates an expected call of Watch
func (mr *MockEtcdClientMockRecorder) Watch(ctx, key interface{}, opts ...interface{}) *gomock.Call { func (mr *MockEtcdClientMockRecorder) Watch(ctx, key any, opts ...any) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{ctx, key}, opts...) varargs := append([]any{ctx, key}, opts...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Watch", reflect.TypeOf((*MockEtcdClient)(nil).Watch), varargs...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Watch", reflect.TypeOf((*MockEtcdClient)(nil).Watch), varargs...)
} }

View File

@@ -167,7 +167,7 @@ func TestCluster_Watch(t *testing.T) {
assert.Equal(t, "world", kv.Val) assert.Equal(t, "world", kv.Val)
wg.Done() wg.Done()
}).MaxTimes(1) }).MaxTimes(1)
listener.EXPECT().OnDelete(gomock.Any()).Do(func(_ interface{}) { listener.EXPECT().OnDelete(gomock.Any()).Do(func(_ any) {
wg.Done() wg.Done()
}).MaxTimes(1) }).MaxTimes(1)
go c.watch(cli, "any", 0) go c.watch(cli, "any", 0)

View File

@@ -58,7 +58,7 @@ func (m *MocketcdConn) WaitForStateChange(ctx context.Context, sourceState conne
} }
// WaitForStateChange indicates an expected call of WaitForStateChange // WaitForStateChange indicates an expected call of WaitForStateChange
func (mr *MocketcdConnMockRecorder) WaitForStateChange(ctx, sourceState interface{}) *gomock.Call { func (mr *MocketcdConnMockRecorder) WaitForStateChange(ctx, sourceState any) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitForStateChange", reflect.TypeOf((*MocketcdConn)(nil).WaitForStateChange), ctx, sourceState) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitForStateChange", reflect.TypeOf((*MocketcdConn)(nil).WaitForStateChange), ctx, sourceState)
} }

View File

@@ -40,7 +40,7 @@ func (m *MockUpdateListener) OnAdd(kv KV) {
} }
// OnAdd indicates an expected call of OnAdd // OnAdd indicates an expected call of OnAdd
func (mr *MockUpdateListenerMockRecorder) OnAdd(kv interface{}) *gomock.Call { func (mr *MockUpdateListenerMockRecorder) OnAdd(kv any) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnAdd", reflect.TypeOf((*MockUpdateListener)(nil).OnAdd), kv) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnAdd", reflect.TypeOf((*MockUpdateListener)(nil).OnAdd), kv)
} }
@@ -52,7 +52,7 @@ func (m *MockUpdateListener) OnDelete(kv KV) {
} }
// OnDelete indicates an expected call of OnDelete // OnDelete indicates an expected call of OnDelete
func (mr *MockUpdateListenerMockRecorder) OnDelete(kv interface{}) *gomock.Call { func (mr *MockUpdateListenerMockRecorder) OnDelete(kv any) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnDelete", reflect.TypeOf((*MockUpdateListener)(nil).OnDelete), kv) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnDelete", reflect.TypeOf((*MockUpdateListener)(nil).OnDelete), kv)
} }

View File

@@ -125,7 +125,7 @@ func TestPublisher_keepAliveAsyncQuit(t *testing.T) {
cli.EXPECT().KeepAlive(gomock.Any(), id) cli.EXPECT().KeepAlive(gomock.Any(), id)
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(1) wg.Add(1)
cli.EXPECT().Revoke(gomock.Any(), id).Do(func(_, _ interface{}) { cli.EXPECT().Revoke(gomock.Any(), id).Do(func(_, _ any) {
wg.Done() wg.Done()
}) })
pub := NewPublisher(nil, "thekey", "thevalue") pub := NewPublisher(nil, "thekey", "thevalue")
@@ -147,7 +147,7 @@ func TestPublisher_keepAliveAsyncPause(t *testing.T) {
pub := NewPublisher(nil, "thekey", "thevalue") pub := NewPublisher(nil, "thekey", "thevalue")
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(1) wg.Add(1)
cli.EXPECT().Revoke(gomock.Any(), id).Do(func(_, _ interface{}) { cli.EXPECT().Revoke(gomock.Any(), id).Do(func(_, _ any) {
pub.Stop() pub.Stop()
wg.Done() wg.Done()
}) })

View File

@@ -12,7 +12,7 @@ func Wrap(err error, message string) error {
} }
// Wrapf returns an error that wraps err with given format and args. // Wrapf returns an error that wraps err with given format and args.
func Wrapf(err error, format string, args ...interface{}) error { func Wrapf(err error, format string, args ...any) error {
if err == nil { if err == nil {
return nil return nil
} }

View File

@@ -42,7 +42,7 @@ func NewBulkExecutor(execute Execute, opts ...BulkOption) *BulkExecutor {
} }
// Add adds task into be. // Add adds task into be.
func (be *BulkExecutor) Add(task interface{}) error { func (be *BulkExecutor) Add(task any) error {
be.executor.Add(task) be.executor.Add(task)
return nil return nil
} }
@@ -79,22 +79,22 @@ func newBulkOptions() bulkOptions {
} }
type bulkContainer struct { type bulkContainer struct {
tasks []interface{} tasks []any
execute Execute execute Execute
maxTasks int maxTasks int
} }
func (bc *bulkContainer) AddTask(task interface{}) bool { func (bc *bulkContainer) AddTask(task any) bool {
bc.tasks = append(bc.tasks, task) bc.tasks = append(bc.tasks, task)
return len(bc.tasks) >= bc.maxTasks return len(bc.tasks) >= bc.maxTasks
} }
func (bc *bulkContainer) Execute(tasks interface{}) { func (bc *bulkContainer) Execute(tasks any) {
vals := tasks.([]interface{}) vals := tasks.([]any)
bc.execute(vals) bc.execute(vals)
} }
func (bc *bulkContainer) RemoveAll() interface{} { func (bc *bulkContainer) RemoveAll() any {
tasks := bc.tasks tasks := bc.tasks
bc.tasks = nil bc.tasks = nil
return tasks return tasks

View File

@@ -12,7 +12,7 @@ func TestBulkExecutor(t *testing.T) {
var values []int var values []int
var lock sync.Mutex var lock sync.Mutex
executor := NewBulkExecutor(func(items []interface{}) { executor := NewBulkExecutor(func(items []any) {
lock.Lock() lock.Lock()
values = append(values, len(items)) values = append(values, len(items))
lock.Unlock() lock.Unlock()
@@ -40,7 +40,7 @@ func TestBulkExecutorFlushInterval(t *testing.T) {
var wait sync.WaitGroup var wait sync.WaitGroup
wait.Add(1) wait.Add(1)
executor := NewBulkExecutor(func(items []interface{}) { executor := NewBulkExecutor(func(items []any) {
assert.Equal(t, size, len(items)) assert.Equal(t, size, len(items))
wait.Done() wait.Done()
}, WithBulkTasks(caches), WithBulkInterval(time.Millisecond*100)) }, WithBulkTasks(caches), WithBulkInterval(time.Millisecond*100))
@@ -53,7 +53,7 @@ func TestBulkExecutorFlushInterval(t *testing.T) {
} }
func TestBulkExecutorEmpty(t *testing.T) { func TestBulkExecutorEmpty(t *testing.T) {
NewBulkExecutor(func(items []interface{}) { NewBulkExecutor(func(items []any) {
assert.Fail(t, "should not called") assert.Fail(t, "should not called")
}, WithBulkTasks(10), WithBulkInterval(time.Millisecond)) }, WithBulkTasks(10), WithBulkInterval(time.Millisecond))
time.Sleep(time.Millisecond * 100) time.Sleep(time.Millisecond * 100)
@@ -67,7 +67,7 @@ func TestBulkExecutorFlush(t *testing.T) {
var wait sync.WaitGroup var wait sync.WaitGroup
wait.Add(1) wait.Add(1)
be := NewBulkExecutor(func(items []interface{}) { be := NewBulkExecutor(func(items []any) {
assert.Equal(t, tasks, len(items)) assert.Equal(t, tasks, len(items))
wait.Done() wait.Done()
}, WithBulkTasks(caches), WithBulkInterval(time.Minute)) }, WithBulkTasks(caches), WithBulkInterval(time.Minute))
@@ -81,8 +81,8 @@ func TestBulkExecutorFlush(t *testing.T) {
func TestBuldExecutorFlushSlowTasks(t *testing.T) { func TestBuldExecutorFlushSlowTasks(t *testing.T) {
const total = 1500 const total = 1500
lock := new(sync.Mutex) lock := new(sync.Mutex)
result := make([]interface{}, 0, 10000) result := make([]any, 0, 10000)
exec := NewBulkExecutor(func(tasks []interface{}) { exec := NewBulkExecutor(func(tasks []any) {
time.Sleep(time.Millisecond * 100) time.Sleep(time.Millisecond * 100)
lock.Lock() lock.Lock()
defer lock.Unlock() defer lock.Unlock()
@@ -100,7 +100,7 @@ func TestBuldExecutorFlushSlowTasks(t *testing.T) {
func BenchmarkBulkExecutor(b *testing.B) { func BenchmarkBulkExecutor(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
be := NewBulkExecutor(func(tasks []interface{}) { be := NewBulkExecutor(func(tasks []any) {
time.Sleep(time.Millisecond * time.Duration(len(tasks))) time.Sleep(time.Millisecond * time.Duration(len(tasks)))
}) })
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {

View File

@@ -42,7 +42,7 @@ func NewChunkExecutor(execute Execute, opts ...ChunkOption) *ChunkExecutor {
} }
// Add adds task with given chunk size into ce. // Add adds task with given chunk size into ce.
func (ce *ChunkExecutor) Add(task interface{}, size int) error { func (ce *ChunkExecutor) Add(task any, size int) error {
ce.executor.Add(chunk{ ce.executor.Add(chunk{
val: task, val: task,
size: size, size: size,
@@ -82,25 +82,25 @@ func newChunkOptions() chunkOptions {
} }
type chunkContainer struct { type chunkContainer struct {
tasks []interface{} tasks []any
execute Execute execute Execute
size int size int
maxChunkSize int maxChunkSize int
} }
func (bc *chunkContainer) AddTask(task interface{}) bool { func (bc *chunkContainer) AddTask(task any) bool {
ck := task.(chunk) ck := task.(chunk)
bc.tasks = append(bc.tasks, ck.val) bc.tasks = append(bc.tasks, ck.val)
bc.size += ck.size bc.size += ck.size
return bc.size >= bc.maxChunkSize return bc.size >= bc.maxChunkSize
} }
func (bc *chunkContainer) Execute(tasks interface{}) { func (bc *chunkContainer) Execute(tasks any) {
vals := tasks.([]interface{}) vals := tasks.([]any)
bc.execute(vals) bc.execute(vals)
} }
func (bc *chunkContainer) RemoveAll() interface{} { func (bc *chunkContainer) RemoveAll() any {
tasks := bc.tasks tasks := bc.tasks
bc.tasks = nil bc.tasks = nil
bc.size = 0 bc.size = 0
@@ -108,6 +108,6 @@ func (bc *chunkContainer) RemoveAll() interface{} {
} }
type chunk struct { type chunk struct {
val interface{} val any
size int size int
} }

View File

@@ -12,7 +12,7 @@ func TestChunkExecutor(t *testing.T) {
var values []int var values []int
var lock sync.Mutex var lock sync.Mutex
executor := NewChunkExecutor(func(items []interface{}) { executor := NewChunkExecutor(func(items []any) {
lock.Lock() lock.Lock()
values = append(values, len(items)) values = append(values, len(items))
lock.Unlock() lock.Unlock()
@@ -40,7 +40,7 @@ func TestChunkExecutorFlushInterval(t *testing.T) {
var wait sync.WaitGroup var wait sync.WaitGroup
wait.Add(1) wait.Add(1)
executor := NewChunkExecutor(func(items []interface{}) { executor := NewChunkExecutor(func(items []any) {
assert.Equal(t, size, len(items)) assert.Equal(t, size, len(items))
wait.Done() wait.Done()
}, WithChunkBytes(caches), WithFlushInterval(time.Millisecond*100)) }, WithChunkBytes(caches), WithFlushInterval(time.Millisecond*100))
@@ -53,10 +53,11 @@ func TestChunkExecutorFlushInterval(t *testing.T) {
} }
func TestChunkExecutorEmpty(t *testing.T) { func TestChunkExecutorEmpty(t *testing.T) {
NewChunkExecutor(func(items []interface{}) { executor := NewChunkExecutor(func(items []any) {
assert.Fail(t, "should not called") assert.Fail(t, "should not called")
}, WithChunkBytes(10), WithFlushInterval(time.Millisecond)) }, WithChunkBytes(10), WithFlushInterval(time.Millisecond))
time.Sleep(time.Millisecond * 100) time.Sleep(time.Millisecond * 100)
executor.Wait()
} }
func TestChunkExecutorFlush(t *testing.T) { func TestChunkExecutorFlush(t *testing.T) {
@@ -67,7 +68,7 @@ func TestChunkExecutorFlush(t *testing.T) {
var wait sync.WaitGroup var wait sync.WaitGroup
wait.Add(1) wait.Add(1)
be := NewChunkExecutor(func(items []interface{}) { be := NewChunkExecutor(func(items []any) {
assert.Equal(t, tasks, len(items)) assert.Equal(t, tasks, len(items))
wait.Done() wait.Done()
}, WithChunkBytes(caches), WithFlushInterval(time.Minute)) }, WithChunkBytes(caches), WithFlushInterval(time.Minute))
@@ -81,7 +82,7 @@ func TestChunkExecutorFlush(t *testing.T) {
func BenchmarkChunkExecutor(b *testing.B) { func BenchmarkChunkExecutor(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
be := NewChunkExecutor(func(tasks []interface{}) { be := NewChunkExecutor(func(tasks []any) {
time.Sleep(time.Millisecond * time.Duration(len(tasks))) time.Sleep(time.Millisecond * time.Duration(len(tasks)))
}) })
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {

View File

@@ -21,16 +21,16 @@ type (
TaskContainer interface { TaskContainer interface {
// AddTask adds the task into the container. // AddTask adds the task into the container.
// Returns true if the container needs to be flushed after the addition. // Returns true if the container needs to be flushed after the addition.
AddTask(task interface{}) bool AddTask(task any) bool
// Execute handles the collected tasks by the container when flushing. // Execute handles the collected tasks by the container when flushing.
Execute(tasks interface{}) Execute(tasks any)
// RemoveAll removes the contained tasks, and return them. // RemoveAll removes the contained tasks, and return them.
RemoveAll() interface{} RemoveAll() any
} }
// A PeriodicalExecutor is an executor that periodically execute tasks. // A PeriodicalExecutor is an executor that periodically execute tasks.
PeriodicalExecutor struct { PeriodicalExecutor struct {
commander chan interface{} commander chan any
interval time.Duration interval time.Duration
container TaskContainer container TaskContainer
waitGroup sync.WaitGroup waitGroup sync.WaitGroup
@@ -48,7 +48,7 @@ type (
func NewPeriodicalExecutor(interval time.Duration, container TaskContainer) *PeriodicalExecutor { func NewPeriodicalExecutor(interval time.Duration, container TaskContainer) *PeriodicalExecutor {
executor := &PeriodicalExecutor{ executor := &PeriodicalExecutor{
// buffer 1 to let the caller go quickly // buffer 1 to let the caller go quickly
commander: make(chan interface{}, 1), commander: make(chan any, 1),
interval: interval, interval: interval,
container: container, container: container,
confirmChan: make(chan lang.PlaceholderType), confirmChan: make(chan lang.PlaceholderType),
@@ -64,7 +64,7 @@ func NewPeriodicalExecutor(interval time.Duration, container TaskContainer) *Per
} }
// Add adds tasks into pe. // Add adds tasks into pe.
func (pe *PeriodicalExecutor) Add(task interface{}) { func (pe *PeriodicalExecutor) Add(task any) {
if vals, ok := pe.addAndCheck(task); ok { if vals, ok := pe.addAndCheck(task); ok {
pe.commander <- vals pe.commander <- vals
<-pe.confirmChan <-pe.confirmChan
@@ -74,7 +74,7 @@ func (pe *PeriodicalExecutor) Add(task interface{}) {
// Flush forces pe to execute tasks. // Flush forces pe to execute tasks.
func (pe *PeriodicalExecutor) Flush() bool { func (pe *PeriodicalExecutor) Flush() bool {
pe.enterExecution() pe.enterExecution()
return pe.executeTasks(func() interface{} { return pe.executeTasks(func() any {
pe.lock.Lock() pe.lock.Lock()
defer pe.lock.Unlock() defer pe.lock.Unlock()
return pe.container.RemoveAll() return pe.container.RemoveAll()
@@ -96,7 +96,7 @@ func (pe *PeriodicalExecutor) Wait() {
}) })
} }
func (pe *PeriodicalExecutor) addAndCheck(task interface{}) (interface{}, bool) { func (pe *PeriodicalExecutor) addAndCheck(task any) (any, bool) {
pe.lock.Lock() pe.lock.Lock()
defer func() { defer func() {
if !pe.guarded { if !pe.guarded {
@@ -157,7 +157,7 @@ func (pe *PeriodicalExecutor) enterExecution() {
}) })
} }
func (pe *PeriodicalExecutor) executeTasks(tasks interface{}) bool { func (pe *PeriodicalExecutor) executeTasks(tasks any) bool {
defer pe.doneExecution() defer pe.doneExecution()
ok := pe.hasTasks(tasks) ok := pe.hasTasks(tasks)
@@ -168,7 +168,7 @@ func (pe *PeriodicalExecutor) executeTasks(tasks interface{}) bool {
return ok return ok
} }
func (pe *PeriodicalExecutor) hasTasks(tasks interface{}) bool { func (pe *PeriodicalExecutor) hasTasks(tasks any) bool {
if tasks == nil { if tasks == nil {
return false return false
} }

View File

@@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/proc"
"github.com/zeromicro/go-zero/core/timex" "github.com/zeromicro/go-zero/core/timex"
) )
@@ -16,22 +17,22 @@ const threshold = 10
type container struct { type container struct {
interval time.Duration interval time.Duration
tasks []int tasks []int
execute func(tasks interface{}) execute func(tasks any)
} }
func newContainer(interval time.Duration, execute func(tasks interface{})) *container { func newContainer(interval time.Duration, execute func(tasks any)) *container {
return &container{ return &container{
interval: interval, interval: interval,
execute: execute, execute: execute,
} }
} }
func (c *container) AddTask(task interface{}) bool { func (c *container) AddTask(task any) bool {
c.tasks = append(c.tasks, task.(int)) c.tasks = append(c.tasks, task.(int))
return len(c.tasks) > threshold return len(c.tasks) > threshold
} }
func (c *container) Execute(tasks interface{}) { func (c *container) Execute(tasks any) {
if c.execute != nil { if c.execute != nil {
c.execute(tasks) c.execute(tasks)
} else { } else {
@@ -39,7 +40,7 @@ func (c *container) Execute(tasks interface{}) {
} }
} }
func (c *container) RemoveAll() interface{} { func (c *container) RemoveAll() any {
tasks := c.tasks tasks := c.tasks
c.tasks = nil c.tasks = nil
return tasks return tasks
@@ -67,6 +68,7 @@ func TestPeriodicalExecutor_QuitGoroutine(t *testing.T) {
ticker.Tick() ticker.Tick()
ticker.Wait(time.Millisecond * idleRound) ticker.Wait(time.Millisecond * idleRound)
assert.Equal(t, routines, runtime.NumGoroutine()) assert.Equal(t, routines, runtime.NumGoroutine())
proc.Shutdown()
} }
func TestPeriodicalExecutor_Bulk(t *testing.T) { func TestPeriodicalExecutor_Bulk(t *testing.T) {
@@ -74,7 +76,7 @@ func TestPeriodicalExecutor_Bulk(t *testing.T) {
var vals []int var vals []int
// avoid data race // avoid data race
var lock sync.Mutex var lock sync.Mutex
exec := NewPeriodicalExecutor(time.Millisecond, newContainer(time.Millisecond, func(tasks interface{}) { exec := NewPeriodicalExecutor(time.Millisecond, newContainer(time.Millisecond, func(tasks any) {
t := tasks.([]int) t := tasks.([]int)
for _, each := range t { for _, each := range t {
lock.Lock() lock.Lock()
@@ -108,7 +110,7 @@ func TestPeriodicalExecutor_Bulk(t *testing.T) {
func TestPeriodicalExecutor_Wait(t *testing.T) { func TestPeriodicalExecutor_Wait(t *testing.T) {
var lock sync.Mutex var lock sync.Mutex
executer := NewBulkExecutor(func(tasks []interface{}) { executer := NewBulkExecutor(func(tasks []any) {
lock.Lock() lock.Lock()
defer lock.Unlock() defer lock.Unlock()
time.Sleep(10 * time.Millisecond) time.Sleep(10 * time.Millisecond)
@@ -124,7 +126,7 @@ func TestPeriodicalExecutor_WaitFast(t *testing.T) {
const total = 3 const total = 3
var cnt int var cnt int
var lock sync.Mutex var lock sync.Mutex
executer := NewBulkExecutor(func(tasks []interface{}) { executer := NewBulkExecutor(func(tasks []any) {
defer func() { defer func() {
cnt++ cnt++
}() }()
@@ -141,7 +143,7 @@ func TestPeriodicalExecutor_WaitFast(t *testing.T) {
} }
func TestPeriodicalExecutor_Deadlock(t *testing.T) { func TestPeriodicalExecutor_Deadlock(t *testing.T) {
executor := NewBulkExecutor(func(tasks []interface{}) { executor := NewBulkExecutor(func(tasks []any) {
}, WithBulkTasks(1), WithBulkInterval(time.Millisecond)) }, WithBulkTasks(1), WithBulkInterval(time.Millisecond))
for i := 0; i < 1e5; i++ { for i := 0; i < 1e5; i++ {
executor.Add(1) executor.Add(1)

View File

@@ -5,4 +5,4 @@ import "time"
const defaultFlushInterval = time.Second const defaultFlushInterval = time.Second
// Execute defines the method to execute tasks. // Execute defines the method to execute tasks.
type Execute func(tasks []interface{}) type Execute func(tasks []any)

View File

@@ -21,31 +21,31 @@ type (
} }
// FilterFunc defines the method to filter a Stream. // FilterFunc defines the method to filter a Stream.
FilterFunc func(item interface{}) bool FilterFunc func(item any) bool
// ForAllFunc defines the method to handle all elements in a Stream. // ForAllFunc defines the method to handle all elements in a Stream.
ForAllFunc func(pipe <-chan interface{}) ForAllFunc func(pipe <-chan any)
// ForEachFunc defines the method to handle each element in a Stream. // ForEachFunc defines the method to handle each element in a Stream.
ForEachFunc func(item interface{}) ForEachFunc func(item any)
// GenerateFunc defines the method to send elements into a Stream. // GenerateFunc defines the method to send elements into a Stream.
GenerateFunc func(source chan<- interface{}) GenerateFunc func(source chan<- any)
// KeyFunc defines the method to generate keys for the elements in a Stream. // KeyFunc defines the method to generate keys for the elements in a Stream.
KeyFunc func(item interface{}) interface{} KeyFunc func(item any) any
// LessFunc defines the method to compare the elements in a Stream. // LessFunc defines the method to compare the elements in a Stream.
LessFunc func(a, b interface{}) bool LessFunc func(a, b any) bool
// MapFunc defines the method to map each element to another object in a Stream. // MapFunc defines the method to map each element to another object in a Stream.
MapFunc func(item interface{}) interface{} MapFunc func(item any) any
// Option defines the method to customize a Stream. // Option defines the method to customize a Stream.
Option func(opts *rxOptions) Option func(opts *rxOptions)
// ParallelFunc defines the method to handle elements parallelly. // ParallelFunc defines the method to handle elements parallelly.
ParallelFunc func(item interface{}) ParallelFunc func(item any)
// ReduceFunc defines the method to reduce all the elements in a Stream. // ReduceFunc defines the method to reduce all the elements in a Stream.
ReduceFunc func(pipe <-chan interface{}) (interface{}, error) ReduceFunc func(pipe <-chan any) (any, error)
// WalkFunc defines the method to walk through all the elements in a Stream. // WalkFunc defines the method to walk through all the elements in a Stream.
WalkFunc func(item interface{}, pipe chan<- interface{}) WalkFunc func(item any, pipe chan<- any)
// A Stream is a stream that can be used to do stream processing. // A Stream is a stream that can be used to do stream processing.
Stream struct { Stream struct {
source <-chan interface{} source <-chan any
} }
) )
@@ -56,7 +56,7 @@ func Concat(s Stream, others ...Stream) Stream {
// From constructs a Stream from the given GenerateFunc. // From constructs a Stream from the given GenerateFunc.
func From(generate GenerateFunc) Stream { func From(generate GenerateFunc) Stream {
source := make(chan interface{}) source := make(chan any)
threading.GoSafe(func() { threading.GoSafe(func() {
defer close(source) defer close(source)
@@ -67,8 +67,8 @@ func From(generate GenerateFunc) Stream {
} }
// Just converts the given arbitrary items to a Stream. // Just converts the given arbitrary items to a Stream.
func Just(items ...interface{}) Stream { func Just(items ...any) Stream {
source := make(chan interface{}, len(items)) source := make(chan any, len(items))
for _, item := range items { for _, item := range items {
source <- item source <- item
} }
@@ -78,7 +78,7 @@ func Just(items ...interface{}) Stream {
} }
// Range converts the given channel to a Stream. // Range converts the given channel to a Stream.
func Range(source <-chan interface{}) Stream { func Range(source <-chan any) Stream {
return Stream{ return Stream{
source: source, source: source,
} }
@@ -87,7 +87,7 @@ func Range(source <-chan interface{}) Stream {
// AllMach returns whether all elements of this stream match the provided predicate. // AllMach returns whether all elements of this stream match the provided predicate.
// May not evaluate the predicate on all elements if not necessary for determining the result. // May not evaluate the predicate on all elements if not necessary for determining the result.
// If the stream is empty then true is returned and the predicate is not evaluated. // If the stream is empty then true is returned and the predicate is not evaluated.
func (s Stream) AllMach(predicate func(item interface{}) bool) bool { func (s Stream) AllMach(predicate func(item any) bool) bool {
for item := range s.source { for item := range s.source {
if !predicate(item) { if !predicate(item) {
// make sure the former goroutine not block, and current func returns fast. // make sure the former goroutine not block, and current func returns fast.
@@ -102,7 +102,7 @@ func (s Stream) AllMach(predicate func(item interface{}) bool) bool {
// AnyMach returns whether any elements of this stream match the provided predicate. // AnyMach returns whether any elements of this stream match the provided predicate.
// May not evaluate the predicate on all elements if not necessary for determining the result. // May not evaluate the predicate on all elements if not necessary for determining the result.
// If the stream is empty then false is returned and the predicate is not evaluated. // If the stream is empty then false is returned and the predicate is not evaluated.
func (s Stream) AnyMach(predicate func(item interface{}) bool) bool { func (s Stream) AnyMach(predicate func(item any) bool) bool {
for item := range s.source { for item := range s.source {
if predicate(item) { if predicate(item) {
// make sure the former goroutine not block, and current func returns fast. // make sure the former goroutine not block, and current func returns fast.
@@ -121,7 +121,7 @@ func (s Stream) Buffer(n int) Stream {
n = 0 n = 0
} }
source := make(chan interface{}, n) source := make(chan any, n)
go func() { go func() {
for item := range s.source { for item := range s.source {
source <- item source <- item
@@ -134,7 +134,7 @@ func (s Stream) Buffer(n int) Stream {
// Concat returns a Stream that concatenated other streams // Concat returns a Stream that concatenated other streams
func (s Stream) Concat(others ...Stream) Stream { func (s Stream) Concat(others ...Stream) Stream {
source := make(chan interface{}) source := make(chan any)
go func() { go func() {
group := threading.NewRoutineGroup() group := threading.NewRoutineGroup()
@@ -170,12 +170,12 @@ func (s Stream) Count() (count int) {
// Distinct removes the duplicated items base on the given KeyFunc. // Distinct removes the duplicated items base on the given KeyFunc.
func (s Stream) Distinct(fn KeyFunc) Stream { func (s Stream) Distinct(fn KeyFunc) Stream {
source := make(chan interface{}) source := make(chan any)
threading.GoSafe(func() { threading.GoSafe(func() {
defer close(source) defer close(source)
keys := make(map[interface{}]lang.PlaceholderType) keys := make(map[any]lang.PlaceholderType)
for item := range s.source { for item := range s.source {
key := fn(item) key := fn(item)
if _, ok := keys[key]; !ok { if _, ok := keys[key]; !ok {
@@ -195,7 +195,7 @@ func (s Stream) Done() {
// Filter filters the items by the given FilterFunc. // Filter filters the items by the given FilterFunc.
func (s Stream) Filter(fn FilterFunc, opts ...Option) Stream { func (s Stream) Filter(fn FilterFunc, opts ...Option) Stream {
return s.Walk(func(item interface{}, pipe chan<- interface{}) { return s.Walk(func(item any, pipe chan<- any) {
if fn(item) { if fn(item) {
pipe <- item pipe <- item
} }
@@ -203,7 +203,7 @@ func (s Stream) Filter(fn FilterFunc, opts ...Option) Stream {
} }
// First returns the first item, nil if no items. // First returns the first item, nil if no items.
func (s Stream) First() interface{} { func (s Stream) First() any {
for item := range s.source { for item := range s.source {
// make sure the former goroutine not block, and current func returns fast. // make sure the former goroutine not block, and current func returns fast.
go drain(s.source) go drain(s.source)
@@ -229,13 +229,13 @@ func (s Stream) ForEach(fn ForEachFunc) {
// Group groups the elements into different groups based on their keys. // Group groups the elements into different groups based on their keys.
func (s Stream) Group(fn KeyFunc) Stream { func (s Stream) Group(fn KeyFunc) Stream {
groups := make(map[interface{}][]interface{}) groups := make(map[any][]any)
for item := range s.source { for item := range s.source {
key := fn(item) key := fn(item)
groups[key] = append(groups[key], item) groups[key] = append(groups[key], item)
} }
source := make(chan interface{}) source := make(chan any)
go func() { go func() {
for _, group := range groups { for _, group := range groups {
source <- group source <- group
@@ -252,7 +252,7 @@ func (s Stream) Head(n int64) Stream {
panic("n must be greater than 0") panic("n must be greater than 0")
} }
source := make(chan interface{}) source := make(chan any)
go func() { go func() {
for item := range s.source { for item := range s.source {
@@ -279,7 +279,7 @@ func (s Stream) Head(n int64) Stream {
} }
// Last returns the last item, or nil if no items. // Last returns the last item, or nil if no items.
func (s Stream) Last() (item interface{}) { func (s Stream) Last() (item any) {
for item = range s.source { for item = range s.source {
} }
return return
@@ -287,19 +287,19 @@ func (s Stream) Last() (item interface{}) {
// Map converts each item to another corresponding item, which means it's a 1:1 model. // Map converts each item to another corresponding item, which means it's a 1:1 model.
func (s Stream) Map(fn MapFunc, opts ...Option) Stream { func (s Stream) Map(fn MapFunc, opts ...Option) Stream {
return s.Walk(func(item interface{}, pipe chan<- interface{}) { return s.Walk(func(item any, pipe chan<- any) {
pipe <- fn(item) pipe <- fn(item)
}, opts...) }, opts...)
} }
// Merge merges all the items into a slice and generates a new stream. // Merge merges all the items into a slice and generates a new stream.
func (s Stream) Merge() Stream { func (s Stream) Merge() Stream {
var items []interface{} var items []any
for item := range s.source { for item := range s.source {
items = append(items, item) items = append(items, item)
} }
source := make(chan interface{}, 1) source := make(chan any, 1)
source <- items source <- items
close(source) close(source)
@@ -309,7 +309,7 @@ func (s Stream) Merge() Stream {
// NoneMatch returns whether all elements of this stream don't match the provided predicate. // NoneMatch returns whether all elements of this stream don't match the provided predicate.
// May not evaluate the predicate on all elements if not necessary for determining the result. // May not evaluate the predicate on all elements if not necessary for determining the result.
// If the stream is empty then true is returned and the predicate is not evaluated. // If the stream is empty then true is returned and the predicate is not evaluated.
func (s Stream) NoneMatch(predicate func(item interface{}) bool) bool { func (s Stream) NoneMatch(predicate func(item any) bool) bool {
for item := range s.source { for item := range s.source {
if predicate(item) { if predicate(item) {
// make sure the former goroutine not block, and current func returns fast. // make sure the former goroutine not block, and current func returns fast.
@@ -323,19 +323,19 @@ func (s Stream) NoneMatch(predicate func(item interface{}) bool) bool {
// Parallel applies the given ParallelFunc to each item concurrently with given number of workers. // Parallel applies the given ParallelFunc to each item concurrently with given number of workers.
func (s Stream) Parallel(fn ParallelFunc, opts ...Option) { func (s Stream) Parallel(fn ParallelFunc, opts ...Option) {
s.Walk(func(item interface{}, pipe chan<- interface{}) { s.Walk(func(item any, pipe chan<- any) {
fn(item) fn(item)
}, opts...).Done() }, opts...).Done()
} }
// Reduce is an utility method to let the caller deal with the underlying channel. // Reduce is an utility method to let the caller deal with the underlying channel.
func (s Stream) Reduce(fn ReduceFunc) (interface{}, error) { func (s Stream) Reduce(fn ReduceFunc) (any, error) {
return fn(s.source) return fn(s.source)
} }
// Reverse reverses the elements in the stream. // Reverse reverses the elements in the stream.
func (s Stream) Reverse() Stream { func (s Stream) Reverse() Stream {
var items []interface{} var items []any
for item := range s.source { for item := range s.source {
items = append(items, item) items = append(items, item)
} }
@@ -357,7 +357,7 @@ func (s Stream) Skip(n int64) Stream {
return s return s
} }
source := make(chan interface{}) source := make(chan any)
go func() { go func() {
for item := range s.source { for item := range s.source {
@@ -376,7 +376,7 @@ func (s Stream) Skip(n int64) Stream {
// Sort sorts the items from the underlying source. // Sort sorts the items from the underlying source.
func (s Stream) Sort(less LessFunc) Stream { func (s Stream) Sort(less LessFunc) Stream {
var items []interface{} var items []any
for item := range s.source { for item := range s.source {
items = append(items, item) items = append(items, item)
} }
@@ -394,9 +394,9 @@ func (s Stream) Split(n int) Stream {
panic("n should be greater than 0") panic("n should be greater than 0")
} }
source := make(chan interface{}) source := make(chan any)
go func() { go func() {
var chunk []interface{} var chunk []any
for item := range s.source { for item := range s.source {
chunk = append(chunk, item) chunk = append(chunk, item)
if len(chunk) == n { if len(chunk) == n {
@@ -419,7 +419,7 @@ func (s Stream) Tail(n int64) Stream {
panic("n should be greater than 0") panic("n should be greater than 0")
} }
source := make(chan interface{}) source := make(chan any)
go func() { go func() {
ring := collection.NewRing(int(n)) ring := collection.NewRing(int(n))
@@ -446,7 +446,7 @@ func (s Stream) Walk(fn WalkFunc, opts ...Option) Stream {
} }
func (s Stream) walkLimited(fn WalkFunc, option *rxOptions) Stream { func (s Stream) walkLimited(fn WalkFunc, option *rxOptions) Stream {
pipe := make(chan interface{}, option.workers) pipe := make(chan any, option.workers)
go func() { go func() {
var wg sync.WaitGroup var wg sync.WaitGroup
@@ -477,7 +477,7 @@ func (s Stream) walkLimited(fn WalkFunc, option *rxOptions) Stream {
} }
func (s Stream) walkUnlimited(fn WalkFunc, option *rxOptions) Stream { func (s Stream) walkUnlimited(fn WalkFunc, option *rxOptions) Stream {
pipe := make(chan interface{}, option.workers) pipe := make(chan any, option.workers)
go func() { go func() {
var wg sync.WaitGroup var wg sync.WaitGroup
@@ -529,7 +529,7 @@ func buildOptions(opts ...Option) *rxOptions {
} }
// drain drains the given channel. // drain drains the given channel.
func drain(channel <-chan interface{}) { func drain(channel <-chan any) {
for range channel { for range channel {
} }
} }

View File

@@ -23,7 +23,7 @@ func TestBuffer(t *testing.T) {
var count int32 var count int32
var wait sync.WaitGroup var wait sync.WaitGroup
wait.Add(1) wait.Add(1)
From(func(source chan<- interface{}) { From(func(source chan<- any) {
ticker := time.NewTicker(10 * time.Millisecond) ticker := time.NewTicker(10 * time.Millisecond)
defer ticker.Stop() defer ticker.Stop()
@@ -36,7 +36,7 @@ func TestBuffer(t *testing.T) {
return return
} }
} }
}).Buffer(N).ForAll(func(pipe <-chan interface{}) { }).Buffer(N).ForAll(func(pipe <-chan any) {
wait.Wait() wait.Wait()
// why N+1, because take one more to wait for sending into the channel // why N+1, because take one more to wait for sending into the channel
assert.Equal(t, int32(N+1), atomic.LoadInt32(&count)) assert.Equal(t, int32(N+1), atomic.LoadInt32(&count))
@@ -47,7 +47,7 @@ func TestBuffer(t *testing.T) {
func TestBufferNegative(t *testing.T) { func TestBufferNegative(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
var result int var result int
Just(1, 2, 3, 4).Buffer(-1).Reduce(func(pipe <-chan interface{}) (interface{}, error) { Just(1, 2, 3, 4).Buffer(-1).Reduce(func(pipe <-chan any) (any, error) {
for item := range pipe { for item := range pipe {
result += item.(int) result += item.(int)
} }
@@ -61,22 +61,22 @@ func TestCount(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
elements []interface{} elements []any
}{ }{
{ {
name: "no elements with nil", name: "no elements with nil",
}, },
{ {
name: "no elements", name: "no elements",
elements: []interface{}{}, elements: []any{},
}, },
{ {
name: "1 element", name: "1 element",
elements: []interface{}{1}, elements: []any{1},
}, },
{ {
name: "multiple elements", name: "multiple elements",
elements: []interface{}{1, 2, 3}, elements: []any{1, 2, 3},
}, },
} }
@@ -92,7 +92,7 @@ func TestCount(t *testing.T) {
func TestDone(t *testing.T) { func TestDone(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
var count int32 var count int32
Just(1, 2, 3).Walk(func(item interface{}, pipe chan<- interface{}) { Just(1, 2, 3).Walk(func(item any, pipe chan<- any) {
time.Sleep(time.Millisecond * 100) time.Sleep(time.Millisecond * 100)
atomic.AddInt32(&count, int32(item.(int))) atomic.AddInt32(&count, int32(item.(int)))
}).Done() }).Done()
@@ -103,7 +103,7 @@ func TestDone(t *testing.T) {
func TestJust(t *testing.T) { func TestJust(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
var result int var result int
Just(1, 2, 3, 4).Reduce(func(pipe <-chan interface{}) (interface{}, error) { Just(1, 2, 3, 4).Reduce(func(pipe <-chan any) (any, error) {
for item := range pipe { for item := range pipe {
result += item.(int) result += item.(int)
} }
@@ -116,9 +116,9 @@ func TestJust(t *testing.T) {
func TestDistinct(t *testing.T) { func TestDistinct(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
var result int var result int
Just(4, 1, 3, 2, 3, 4).Distinct(func(item interface{}) interface{} { Just(4, 1, 3, 2, 3, 4).Distinct(func(item any) any {
return item return item
}).Reduce(func(pipe <-chan interface{}) (interface{}, error) { }).Reduce(func(pipe <-chan any) (any, error) {
for item := range pipe { for item := range pipe {
result += item.(int) result += item.(int)
} }
@@ -131,9 +131,9 @@ func TestDistinct(t *testing.T) {
func TestFilter(t *testing.T) { func TestFilter(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
var result int var result int
Just(1, 2, 3, 4).Filter(func(item interface{}) bool { Just(1, 2, 3, 4).Filter(func(item any) bool {
return item.(int)%2 == 0 return item.(int)%2 == 0
}).Reduce(func(pipe <-chan interface{}) (interface{}, error) { }).Reduce(func(pipe <-chan any) (any, error) {
for item := range pipe { for item := range pipe {
result += item.(int) result += item.(int)
} }
@@ -154,9 +154,9 @@ func TestFirst(t *testing.T) {
func TestForAll(t *testing.T) { func TestForAll(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
var result int var result int
Just(1, 2, 3, 4).Filter(func(item interface{}) bool { Just(1, 2, 3, 4).Filter(func(item any) bool {
return item.(int)%2 == 0 return item.(int)%2 == 0
}).ForAll(func(pipe <-chan interface{}) { }).ForAll(func(pipe <-chan any) {
for item := range pipe { for item := range pipe {
result += item.(int) result += item.(int)
} }
@@ -168,11 +168,11 @@ func TestForAll(t *testing.T) {
func TestGroup(t *testing.T) { func TestGroup(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
var groups [][]int var groups [][]int
Just(10, 11, 20, 21).Group(func(item interface{}) interface{} { Just(10, 11, 20, 21).Group(func(item any) any {
v := item.(int) v := item.(int)
return v / 10 return v / 10
}).ForEach(func(item interface{}) { }).ForEach(func(item any) {
v := item.([]interface{}) v := item.([]any)
var group []int var group []int
for _, each := range v { for _, each := range v {
group = append(group, each.(int)) group = append(group, each.(int))
@@ -191,7 +191,7 @@ func TestGroup(t *testing.T) {
func TestHead(t *testing.T) { func TestHead(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
var result int var result int
Just(1, 2, 3, 4).Head(2).Reduce(func(pipe <-chan interface{}) (interface{}, error) { Just(1, 2, 3, 4).Head(2).Reduce(func(pipe <-chan any) (any, error) {
for item := range pipe { for item := range pipe {
result += item.(int) result += item.(int)
} }
@@ -204,7 +204,7 @@ func TestHead(t *testing.T) {
func TestHeadZero(t *testing.T) { func TestHeadZero(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
assert.Panics(t, func() { assert.Panics(t, func() {
Just(1, 2, 3, 4).Head(0).Reduce(func(pipe <-chan interface{}) (interface{}, error) { Just(1, 2, 3, 4).Head(0).Reduce(func(pipe <-chan any) (any, error) {
return nil, nil return nil, nil
}) })
}) })
@@ -214,7 +214,7 @@ func TestHeadZero(t *testing.T) {
func TestHeadMore(t *testing.T) { func TestHeadMore(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
var result int var result int
Just(1, 2, 3, 4).Head(6).Reduce(func(pipe <-chan interface{}) (interface{}, error) { Just(1, 2, 3, 4).Head(6).Reduce(func(pipe <-chan any) (any, error) {
for item := range pipe { for item := range pipe {
result += item.(int) result += item.(int)
} }
@@ -245,14 +245,14 @@ func TestMap(t *testing.T) {
expect int expect int
}{ }{
{ {
mapper: func(item interface{}) interface{} { mapper: func(item any) any {
v := item.(int) v := item.(int)
return v * v return v * v
}, },
expect: 30, expect: 30,
}, },
{ {
mapper: func(item interface{}) interface{} { mapper: func(item any) any {
v := item.(int) v := item.(int)
if v%2 == 0 { if v%2 == 0 {
return 0 return 0
@@ -262,7 +262,7 @@ func TestMap(t *testing.T) {
expect: 10, expect: 10,
}, },
{ {
mapper: func(item interface{}) interface{} { mapper: func(item any) any {
v := item.(int) v := item.(int)
if v%2 == 0 { if v%2 == 0 {
panic(v) panic(v)
@@ -283,12 +283,12 @@ func TestMap(t *testing.T) {
} else { } else {
workers = runtime.NumCPU() workers = runtime.NumCPU()
} }
From(func(source chan<- interface{}) { From(func(source chan<- any) {
for i := 1; i < 5; i++ { for i := 1; i < 5; i++ {
source <- i source <- i
} }
}).Map(test.mapper, WithWorkers(workers)).Reduce( }).Map(test.mapper, WithWorkers(workers)).Reduce(
func(pipe <-chan interface{}) (interface{}, error) { func(pipe <-chan any) (any, error) {
for item := range pipe { for item := range pipe {
result += item.(int) result += item.(int)
} }
@@ -303,8 +303,8 @@ func TestMap(t *testing.T) {
func TestMerge(t *testing.T) { func TestMerge(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
Just(1, 2, 3, 4).Merge().ForEach(func(item interface{}) { Just(1, 2, 3, 4).Merge().ForEach(func(item any) {
assert.ElementsMatch(t, []interface{}{1, 2, 3, 4}, item.([]interface{})) assert.ElementsMatch(t, []any{1, 2, 3, 4}, item.([]any))
}) })
}) })
} }
@@ -312,7 +312,7 @@ func TestMerge(t *testing.T) {
func TestParallelJust(t *testing.T) { func TestParallelJust(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
var count int32 var count int32
Just(1, 2, 3).Parallel(func(item interface{}) { Just(1, 2, 3).Parallel(func(item any) {
time.Sleep(time.Millisecond * 100) time.Sleep(time.Millisecond * 100)
atomic.AddInt32(&count, int32(item.(int))) atomic.AddInt32(&count, int32(item.(int)))
}, UnlimitedWorkers()) }, UnlimitedWorkers())
@@ -322,8 +322,8 @@ func TestParallelJust(t *testing.T) {
func TestReverse(t *testing.T) { func TestReverse(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
Just(1, 2, 3, 4).Reverse().Merge().ForEach(func(item interface{}) { Just(1, 2, 3, 4).Reverse().Merge().ForEach(func(item any) {
assert.ElementsMatch(t, []interface{}{4, 3, 2, 1}, item.([]interface{})) assert.ElementsMatch(t, []any{4, 3, 2, 1}, item.([]any))
}) })
}) })
} }
@@ -331,9 +331,9 @@ func TestReverse(t *testing.T) {
func TestSort(t *testing.T) { func TestSort(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
var prev int var prev int
Just(5, 3, 7, 1, 9, 6, 4, 8, 2).Sort(func(a, b interface{}) bool { Just(5, 3, 7, 1, 9, 6, 4, 8, 2).Sort(func(a, b any) bool {
return a.(int) < b.(int) return a.(int) < b.(int)
}).ForEach(func(item interface{}) { }).ForEach(func(item any) {
next := item.(int) next := item.(int)
assert.True(t, prev < next) assert.True(t, prev < next)
prev = next prev = next
@@ -346,12 +346,12 @@ func TestSplit(t *testing.T) {
assert.Panics(t, func() { assert.Panics(t, func() {
Just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).Split(0).Done() Just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).Split(0).Done()
}) })
var chunks [][]interface{} var chunks [][]any
Just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).Split(4).ForEach(func(item interface{}) { Just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).Split(4).ForEach(func(item any) {
chunk := item.([]interface{}) chunk := item.([]any)
chunks = append(chunks, chunk) chunks = append(chunks, chunk)
}) })
assert.EqualValues(t, [][]interface{}{ assert.EqualValues(t, [][]any{
{1, 2, 3, 4}, {1, 2, 3, 4},
{5, 6, 7, 8}, {5, 6, 7, 8},
{9, 10}, {9, 10},
@@ -362,7 +362,7 @@ func TestSplit(t *testing.T) {
func TestTail(t *testing.T) { func TestTail(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
var result int var result int
Just(1, 2, 3, 4).Tail(2).Reduce(func(pipe <-chan interface{}) (interface{}, error) { Just(1, 2, 3, 4).Tail(2).Reduce(func(pipe <-chan any) (any, error) {
for item := range pipe { for item := range pipe {
result += item.(int) result += item.(int)
} }
@@ -375,7 +375,7 @@ func TestTail(t *testing.T) {
func TestTailZero(t *testing.T) { func TestTailZero(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
assert.Panics(t, func() { assert.Panics(t, func() {
Just(1, 2, 3, 4).Tail(0).Reduce(func(pipe <-chan interface{}) (interface{}, error) { Just(1, 2, 3, 4).Tail(0).Reduce(func(pipe <-chan any) (any, error) {
return nil, nil return nil, nil
}) })
}) })
@@ -385,11 +385,11 @@ func TestTailZero(t *testing.T) {
func TestWalk(t *testing.T) { func TestWalk(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
var result int var result int
Just(1, 2, 3, 4, 5).Walk(func(item interface{}, pipe chan<- interface{}) { Just(1, 2, 3, 4, 5).Walk(func(item any, pipe chan<- any) {
if item.(int)%2 != 0 { if item.(int)%2 != 0 {
pipe <- item pipe <- item
} }
}, UnlimitedWorkers()).ForEach(func(item interface{}) { }, UnlimitedWorkers()).ForEach(func(item any) {
result += item.(int) result += item.(int)
}) })
assert.Equal(t, 9, result) assert.Equal(t, 9, result)
@@ -398,16 +398,16 @@ func TestWalk(t *testing.T) {
func TestStream_AnyMach(t *testing.T) { func TestStream_AnyMach(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
assetEqual(t, false, Just(1, 2, 3).AnyMach(func(item interface{}) bool { assetEqual(t, false, Just(1, 2, 3).AnyMach(func(item any) bool {
return item.(int) == 4 return item.(int) == 4
})) }))
assetEqual(t, false, Just(1, 2, 3).AnyMach(func(item interface{}) bool { assetEqual(t, false, Just(1, 2, 3).AnyMach(func(item any) bool {
return item.(int) == 0 return item.(int) == 0
})) }))
assetEqual(t, true, Just(1, 2, 3).AnyMach(func(item interface{}) bool { assetEqual(t, true, Just(1, 2, 3).AnyMach(func(item any) bool {
return item.(int) == 2 return item.(int) == 2
})) }))
assetEqual(t, true, Just(1, 2, 3).AnyMach(func(item interface{}) bool { assetEqual(t, true, Just(1, 2, 3).AnyMach(func(item any) bool {
return item.(int) == 2 return item.(int) == 2
})) }))
}) })
@@ -416,17 +416,17 @@ func TestStream_AnyMach(t *testing.T) {
func TestStream_AllMach(t *testing.T) { func TestStream_AllMach(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
assetEqual( assetEqual(
t, true, Just(1, 2, 3).AllMach(func(item interface{}) bool { t, true, Just(1, 2, 3).AllMach(func(item any) bool {
return true return true
}), }),
) )
assetEqual( assetEqual(
t, false, Just(1, 2, 3).AllMach(func(item interface{}) bool { t, false, Just(1, 2, 3).AllMach(func(item any) bool {
return false return false
}), }),
) )
assetEqual( assetEqual(
t, false, Just(1, 2, 3).AllMach(func(item interface{}) bool { t, false, Just(1, 2, 3).AllMach(func(item any) bool {
return item.(int) == 1 return item.(int) == 1
}), }),
) )
@@ -436,17 +436,17 @@ func TestStream_AllMach(t *testing.T) {
func TestStream_NoneMatch(t *testing.T) { func TestStream_NoneMatch(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
assetEqual( assetEqual(
t, true, Just(1, 2, 3).NoneMatch(func(item interface{}) bool { t, true, Just(1, 2, 3).NoneMatch(func(item any) bool {
return false return false
}), }),
) )
assetEqual( assetEqual(
t, false, Just(1, 2, 3).NoneMatch(func(item interface{}) bool { t, false, Just(1, 2, 3).NoneMatch(func(item any) bool {
return true return true
}), }),
) )
assetEqual( assetEqual(
t, true, Just(1, 2, 3).NoneMatch(func(item interface{}) bool { t, true, Just(1, 2, 3).NoneMatch(func(item any) bool {
return item.(int) == 4 return item.(int) == 4
}), }),
) )
@@ -455,19 +455,19 @@ func TestStream_NoneMatch(t *testing.T) {
func TestConcat(t *testing.T) { func TestConcat(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
a1 := []interface{}{1, 2, 3} a1 := []any{1, 2, 3}
a2 := []interface{}{4, 5, 6} a2 := []any{4, 5, 6}
s1 := Just(a1...) s1 := Just(a1...)
s2 := Just(a2...) s2 := Just(a2...)
stream := Concat(s1, s2) stream := Concat(s1, s2)
var items []interface{} var items []any
for item := range stream.source { for item := range stream.source {
items = append(items, item) items = append(items, item)
} }
sort.Slice(items, func(i, j int) bool { sort.Slice(items, func(i, j int) bool {
return items[i].(int) < items[j].(int) return items[i].(int) < items[j].(int)
}) })
ints := make([]interface{}, 0) ints := make([]any, 0)
ints = append(ints, a1...) ints = append(ints, a1...)
ints = append(ints, a2...) ints = append(ints, a2...)
assetEqual(t, ints, items) assetEqual(t, ints, items)
@@ -479,7 +479,7 @@ func TestStream_Skip(t *testing.T) {
assetEqual(t, 3, Just(1, 2, 3, 4).Skip(1).Count()) assetEqual(t, 3, Just(1, 2, 3, 4).Skip(1).Count())
assetEqual(t, 1, Just(1, 2, 3, 4).Skip(3).Count()) assetEqual(t, 1, Just(1, 2, 3, 4).Skip(3).Count())
assetEqual(t, 4, Just(1, 2, 3, 4).Skip(0).Count()) assetEqual(t, 4, Just(1, 2, 3, 4).Skip(0).Count())
equal(t, Just(1, 2, 3, 4).Skip(3), []interface{}{4}) equal(t, Just(1, 2, 3, 4).Skip(3), []any{4})
assert.Panics(t, func() { assert.Panics(t, func() {
Just(1, 2, 3, 4).Skip(-1) Just(1, 2, 3, 4).Skip(-1)
}) })
@@ -489,27 +489,27 @@ func TestStream_Skip(t *testing.T) {
func TestStream_Concat(t *testing.T) { func TestStream_Concat(t *testing.T) {
runCheckedTest(t, func(t *testing.T) { runCheckedTest(t, func(t *testing.T) {
stream := Just(1).Concat(Just(2), Just(3)) stream := Just(1).Concat(Just(2), Just(3))
var items []interface{} var items []any
for item := range stream.source { for item := range stream.source {
items = append(items, item) items = append(items, item)
} }
sort.Slice(items, func(i, j int) bool { sort.Slice(items, func(i, j int) bool {
return items[i].(int) < items[j].(int) return items[i].(int) < items[j].(int)
}) })
assetEqual(t, []interface{}{1, 2, 3}, items) assetEqual(t, []any{1, 2, 3}, items)
just := Just(1) just := Just(1)
equal(t, just.Concat(just), []interface{}{1}) equal(t, just.Concat(just), []any{1})
}) })
} }
func BenchmarkParallelMapReduce(b *testing.B) { func BenchmarkParallelMapReduce(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
mapper := func(v interface{}) interface{} { mapper := func(v any) any {
return v.(int64) * v.(int64) return v.(int64) * v.(int64)
} }
reducer := func(input <-chan interface{}) (interface{}, error) { reducer := func(input <-chan any) (any, error) {
var result int64 var result int64
for v := range input { for v := range input {
result += v.(int64) result += v.(int64)
@@ -517,7 +517,7 @@ func BenchmarkParallelMapReduce(b *testing.B) {
return result, nil return result, nil
} }
b.ResetTimer() b.ResetTimer()
From(func(input chan<- interface{}) { From(func(input chan<- any) {
b.RunParallel(func(pb *testing.PB) { b.RunParallel(func(pb *testing.PB) {
for pb.Next() { for pb.Next() {
input <- int64(rand.Int()) input <- int64(rand.Int())
@@ -529,10 +529,10 @@ func BenchmarkParallelMapReduce(b *testing.B) {
func BenchmarkMapReduce(b *testing.B) { func BenchmarkMapReduce(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
mapper := func(v interface{}) interface{} { mapper := func(v any) any {
return v.(int64) * v.(int64) return v.(int64) * v.(int64)
} }
reducer := func(input <-chan interface{}) (interface{}, error) { reducer := func(input <-chan any) (any, error) {
var result int64 var result int64
for v := range input { for v := range input {
result += v.(int64) result += v.(int64)
@@ -540,21 +540,21 @@ func BenchmarkMapReduce(b *testing.B) {
return result, nil return result, nil
} }
b.ResetTimer() b.ResetTimer()
From(func(input chan<- interface{}) { From(func(input chan<- any) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
input <- int64(rand.Int()) input <- int64(rand.Int())
} }
}).Map(mapper).Reduce(reducer) }).Map(mapper).Reduce(reducer)
} }
func assetEqual(t *testing.T, except, data interface{}) { func assetEqual(t *testing.T, except, data any) {
if !reflect.DeepEqual(except, data) { if !reflect.DeepEqual(except, data) {
t.Errorf(" %v, want %v", data, except) t.Errorf(" %v, want %v", data, except)
} }
} }
func equal(t *testing.T, stream Stream, data []interface{}) { func equal(t *testing.T, stream Stream, data []any) {
items := make([]interface{}, 0) items := make([]any, 0)
for item := range stream.source { for item := range stream.source {
items = append(items, item) items = append(items, item)
} }

View File

@@ -29,7 +29,7 @@ func DoWithTimeout(fn func() error, timeout time.Duration, opts ...DoOption) err
// create channel with buffer size 1 to avoid goroutine leak // create channel with buffer size 1 to avoid goroutine leak
done := make(chan error, 1) done := make(chan error, 1)
panicChan := make(chan interface{}, 1) panicChan := make(chan any, 1)
go func() { go func() {
defer func() { defer func() {
if p := recover(); p != nil { if p := recover(); p != nil {

View File

@@ -26,7 +26,7 @@ type (
hashFunc Func hashFunc Func
replicas int replicas int
keys []uint64 keys []uint64
ring map[uint64][]interface{} ring map[uint64][]any
nodes map[string]lang.PlaceholderType nodes map[string]lang.PlaceholderType
lock sync.RWMutex lock sync.RWMutex
} }
@@ -50,21 +50,21 @@ func NewCustomConsistentHash(replicas int, fn Func) *ConsistentHash {
return &ConsistentHash{ return &ConsistentHash{
hashFunc: fn, hashFunc: fn,
replicas: replicas, replicas: replicas,
ring: make(map[uint64][]interface{}), ring: make(map[uint64][]any),
nodes: make(map[string]lang.PlaceholderType), nodes: make(map[string]lang.PlaceholderType),
} }
} }
// Add adds the node with the number of h.replicas, // Add adds the node with the number of h.replicas,
// the later call will overwrite the replicas of the former calls. // the later call will overwrite the replicas of the former calls.
func (h *ConsistentHash) Add(node interface{}) { func (h *ConsistentHash) Add(node any) {
h.AddWithReplicas(node, h.replicas) h.AddWithReplicas(node, h.replicas)
} }
// AddWithReplicas adds the node with the number of replicas, // AddWithReplicas adds the node with the number of replicas,
// replicas will be truncated to h.replicas if it's larger than h.replicas, // replicas will be truncated to h.replicas if it's larger than h.replicas,
// the later call will overwrite the replicas of the former calls. // the later call will overwrite the replicas of the former calls.
func (h *ConsistentHash) AddWithReplicas(node interface{}, replicas int) { func (h *ConsistentHash) AddWithReplicas(node any, replicas int) {
h.Remove(node) h.Remove(node)
if replicas > h.replicas { if replicas > h.replicas {
@@ -89,7 +89,7 @@ func (h *ConsistentHash) AddWithReplicas(node interface{}, replicas int) {
// AddWithWeight adds the node with weight, the weight can be 1 to 100, indicates the percent, // AddWithWeight adds the node with weight, the weight can be 1 to 100, indicates the percent,
// the later call will overwrite the replicas of the former calls. // the later call will overwrite the replicas of the former calls.
func (h *ConsistentHash) AddWithWeight(node interface{}, weight int) { func (h *ConsistentHash) AddWithWeight(node any, weight int) {
// don't need to make sure weight not larger than TopWeight, // don't need to make sure weight not larger than TopWeight,
// because AddWithReplicas makes sure replicas cannot be larger than h.replicas // because AddWithReplicas makes sure replicas cannot be larger than h.replicas
replicas := h.replicas * weight / TopWeight replicas := h.replicas * weight / TopWeight
@@ -97,7 +97,7 @@ func (h *ConsistentHash) AddWithWeight(node interface{}, weight int) {
} }
// Get returns the corresponding node from h base on the given v. // Get returns the corresponding node from h base on the given v.
func (h *ConsistentHash) Get(v interface{}) (interface{}, bool) { func (h *ConsistentHash) Get(v any) (any, bool) {
h.lock.RLock() h.lock.RLock()
defer h.lock.RUnlock() defer h.lock.RUnlock()
@@ -124,7 +124,7 @@ func (h *ConsistentHash) Get(v interface{}) (interface{}, bool) {
} }
// Remove removes the given node from h. // Remove removes the given node from h.
func (h *ConsistentHash) Remove(node interface{}) { func (h *ConsistentHash) Remove(node any) {
nodeRepr := repr(node) nodeRepr := repr(node)
h.lock.Lock() h.lock.Lock()
@@ -177,10 +177,10 @@ func (h *ConsistentHash) removeNode(nodeRepr string) {
delete(h.nodes, nodeRepr) delete(h.nodes, nodeRepr)
} }
func innerRepr(node interface{}) string { func innerRepr(node any) string {
return fmt.Sprintf("%d:%v", prime, node) return fmt.Sprintf("%d:%v", prime, node)
} }
func repr(node interface{}) string { func repr(node any) string {
return lang.Repr(node) return lang.Repr(node)
} }

View File

@@ -42,7 +42,7 @@ func TestConsistentHash(t *testing.T) {
keys[key.(string)]++ keys[key.(string)]++
} }
mi := make(map[interface{}]int, len(keys)) mi := make(map[any]int, len(keys))
for k, v := range keys { for k, v := range keys {
mi[k] = v mi[k] = v
} }

View File

@@ -16,7 +16,7 @@ func NewBufferPool(capability int) *BufferPool {
return &BufferPool{ return &BufferPool{
capability: capability, capability: capability,
pool: &sync.Pool{ pool: &sync.Pool{
New: func() interface{} { New: func() any {
return new(bytes.Buffer) return new(bytes.Buffer)
}, },
}, },

View File

@@ -9,12 +9,12 @@ import (
) )
// Marshal marshals v into json bytes. // Marshal marshals v into json bytes.
func Marshal(v interface{}) ([]byte, error) { func Marshal(v any) ([]byte, error) {
return json.Marshal(v) return json.Marshal(v)
} }
// MarshalToString marshals v into a string. // MarshalToString marshals v into a string.
func MarshalToString(v interface{}) (string, error) { func MarshalToString(v any) (string, error) {
data, err := Marshal(v) data, err := Marshal(v)
if err != nil { if err != nil {
return "", err return "", err
@@ -24,7 +24,7 @@ func MarshalToString(v interface{}) (string, error) {
} }
// Unmarshal unmarshals data bytes into v. // Unmarshal unmarshals data bytes into v.
func Unmarshal(data []byte, v interface{}) error { func Unmarshal(data []byte, v any) error {
decoder := json.NewDecoder(bytes.NewReader(data)) decoder := json.NewDecoder(bytes.NewReader(data))
if err := unmarshalUseNumber(decoder, v); err != nil { if err := unmarshalUseNumber(decoder, v); err != nil {
return formatError(string(data), err) return formatError(string(data), err)
@@ -34,7 +34,7 @@ func Unmarshal(data []byte, v interface{}) error {
} }
// UnmarshalFromString unmarshals v from str. // UnmarshalFromString unmarshals v from str.
func UnmarshalFromString(str string, v interface{}) error { func UnmarshalFromString(str string, v any) error {
decoder := json.NewDecoder(strings.NewReader(str)) decoder := json.NewDecoder(strings.NewReader(str))
if err := unmarshalUseNumber(decoder, v); err != nil { if err := unmarshalUseNumber(decoder, v); err != nil {
return formatError(str, err) return formatError(str, err)
@@ -44,7 +44,7 @@ func UnmarshalFromString(str string, v interface{}) error {
} }
// UnmarshalFromReader unmarshals v from reader. // UnmarshalFromReader unmarshals v from reader.
func UnmarshalFromReader(reader io.Reader, v interface{}) error { func UnmarshalFromReader(reader io.Reader, v any) error {
var buf strings.Builder var buf strings.Builder
teeReader := io.TeeReader(reader, &buf) teeReader := io.TeeReader(reader, &buf)
decoder := json.NewDecoder(teeReader) decoder := json.NewDecoder(teeReader)
@@ -55,7 +55,7 @@ func UnmarshalFromReader(reader io.Reader, v interface{}) error {
return nil return nil
} }
func unmarshalUseNumber(decoder *json.Decoder, v interface{}) error { func unmarshalUseNumber(decoder *json.Decoder, v any) error {
decoder.UseNumber() decoder.UseNumber()
return decoder.Decode(v) return decoder.Decode(v)
} }

View File

@@ -11,13 +11,13 @@ var Placeholder PlaceholderType
type ( type (
// AnyType can be used to hold any type. // AnyType can be used to hold any type.
AnyType = interface{} AnyType = any
// PlaceholderType represents a placeholder type. // PlaceholderType represents a placeholder type.
PlaceholderType = struct{} PlaceholderType = struct{}
) )
// Repr returns the string representation of v. // Repr returns the string representation of v.
func Repr(v interface{}) string { func Repr(v any) string {
if v == nil { if v == nil {
return "" return ""
} }

View File

@@ -23,7 +23,7 @@ func TestRepr(t *testing.T) {
u64 uint64 = 8 u64 uint64 = 8
) )
tests := []struct { tests := []struct {
v interface{} v any
expect string expect string
}{ }{
{ {

View File

@@ -27,19 +27,39 @@ func Close() error {
return logx.Close() return logx.Close()
} }
// Debug writes v into access log.
func Debug(ctx context.Context, v ...interface{}) {
getLogger(ctx).Debug(v...)
}
// Debugf writes v with format into access log.
func Debugf(ctx context.Context, format string, v ...interface{}) {
getLogger(ctx).Debugf(format, v...)
}
// Debugv writes v into access log with json content.
func Debugv(ctx context.Context, v interface{}) {
getLogger(ctx).Debugv(v)
}
// Debugw writes msg along with fields into access log.
func Debugw(ctx context.Context, msg string, fields ...LogField) {
getLogger(ctx).Debugw(msg, fields...)
}
// Error writes v into error log. // Error writes v into error log.
func Error(ctx context.Context, v ...interface{}) { func Error(ctx context.Context, v ...any) {
getLogger(ctx).Error(v...) getLogger(ctx).Error(v...)
} }
// Errorf writes v with format into error log. // Errorf writes v with format into error log.
func Errorf(ctx context.Context, format string, v ...interface{}) { func Errorf(ctx context.Context, format string, v ...any) {
getLogger(ctx).Errorf(fmt.Errorf(format, v...).Error()) getLogger(ctx).Errorf(fmt.Errorf(format, v...).Error())
} }
// Errorv writes v into error log with json content. // Errorv writes v into error log with json content.
// No call stack attached, because not elegant to pack the messages. // No call stack attached, because not elegant to pack the messages.
func Errorv(ctx context.Context, v interface{}) { func Errorv(ctx context.Context, v any) {
getLogger(ctx).Errorv(v) getLogger(ctx).Errorv(v)
} }
@@ -49,22 +69,22 @@ func Errorw(ctx context.Context, msg string, fields ...LogField) {
} }
// Field returns a LogField for the given key and value. // Field returns a LogField for the given key and value.
func Field(key string, value interface{}) LogField { func Field(key string, value any) LogField {
return logx.Field(key, value) return logx.Field(key, value)
} }
// Info writes v into access log. // Info writes v into access log.
func Info(ctx context.Context, v ...interface{}) { func Info(ctx context.Context, v ...any) {
getLogger(ctx).Info(v...) getLogger(ctx).Info(v...)
} }
// Infof writes v with format into access log. // Infof writes v with format into access log.
func Infof(ctx context.Context, format string, v ...interface{}) { func Infof(ctx context.Context, format string, v ...any) {
getLogger(ctx).Infof(format, v...) getLogger(ctx).Infof(format, v...)
} }
// Infov writes v into access log with json content. // Infov writes v into access log with json content.
func Infov(ctx context.Context, v interface{}) { func Infov(ctx context.Context, v any) {
getLogger(ctx).Infov(v) getLogger(ctx).Infov(v)
} }
@@ -97,17 +117,17 @@ func SetUp(c LogConf) error {
} }
// Slow writes v into slow log. // Slow writes v into slow log.
func Slow(ctx context.Context, v ...interface{}) { func Slow(ctx context.Context, v ...any) {
getLogger(ctx).Slow(v...) getLogger(ctx).Slow(v...)
} }
// Slowf writes v with format into slow log. // Slowf writes v with format into slow log.
func Slowf(ctx context.Context, format string, v ...interface{}) { func Slowf(ctx context.Context, format string, v ...any) {
getLogger(ctx).Slowf(format, v...) getLogger(ctx).Slowf(format, v...)
} }
// Slowv writes v into slow log with json content. // Slowv writes v into slow log with json content.
func Slowv(ctx context.Context, v interface{}) { func Slowv(ctx context.Context, v any) {
getLogger(ctx).Slowv(v) getLogger(ctx).Slowv(v)
} }

View File

@@ -26,7 +26,7 @@ func TestAddGlobalFields(t *testing.T) {
AddGlobalFields(Field("a", "1"), Field("b", "2")) AddGlobalFields(Field("a", "1"), Field("b", "2"))
AddGlobalFields(Field("c", "3")) AddGlobalFields(Field("c", "3"))
Info(context.Background(), "world") Info(context.Background(), "world")
var m map[string]interface{} var m map[string]any
assert.NoError(t, json.Unmarshal(buf.Bytes(), &m)) assert.NoError(t, json.Unmarshal(buf.Bytes(), &m))
assert.Equal(t, "1", m["a"]) assert.Equal(t, "1", m["a"])
assert.Equal(t, "2", m["b"]) assert.Equal(t, "2", m["b"])
@@ -140,6 +140,54 @@ func TestInfow(t *testing.T) {
assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1))) assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1)))
} }
func TestDebug(t *testing.T) {
var buf strings.Builder
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
file, line := getFileLine()
Debug(context.Background(), "foo")
assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1)))
}
func TestDebugf(t *testing.T) {
var buf strings.Builder
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
file, line := getFileLine()
Debugf(context.Background(), "foo %s", "bar")
assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1)))
}
func TestDebugv(t *testing.T) {
var buf strings.Builder
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
file, line := getFileLine()
Debugv(context.Background(), "foo")
assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1)))
}
func TestDebugw(t *testing.T) {
var buf strings.Builder
writer := logx.NewWriter(&buf)
old := logx.Reset()
logx.SetWriter(writer)
defer logx.SetWriter(old)
file, line := getFileLine()
Debugw(context.Background(), "foo", Field("a", "b"))
assert.True(t, strings.Contains(buf.String(), fmt.Sprintf("%s:%d", file, line+1)))
}
func TestMust(t *testing.T) { func TestMust(t *testing.T) {
assert.NotPanics(t, func() { assert.NotPanics(t, func() {
Must(nil) Must(nil)

View File

@@ -2,17 +2,34 @@ package logx
// A LogConf is a logging config. // A LogConf is a logging config.
type LogConf struct { type LogConf struct {
ServiceName string `json:",optional"` // ServiceName represents the service name.
Mode string `json:",default=console,options=[console,file,volume]"` ServiceName string `json:",optional"`
Encoding string `json:",default=json,options=[json,plain]"` // Mode represents the logging mode, default is `console`.
TimeFormat string `json:",optional"` // console: log to console.
Path string `json:",default=logs"` // file: log to file.
Level string `json:",default=info,options=[debug,info,error,severe]"` // volume: used in k8s, prepend the hostname to the log file name.
MaxContentLength uint32 `json:",optional"` Mode string `json:",default=console,options=[console,file,volume]"`
Compress bool `json:",optional"` // Encoding represents the encoding type, default is `json`.
Stat bool `json:",default=true"` // json: json encoding.
KeepDays int `json:",optional"` // plain: plain text encoding, typically used in development.
StackCooldownMillis int `json:",default=100"` Encoding string `json:",default=json,options=[json,plain]"`
// TimeFormat represents the time format, default is `2006-01-02T15:04:05.000Z07:00`.
TimeFormat string `json:",optional"`
// Path represents the log file path, default is `logs`.
Path string `json:",default=logs"`
// Level represents the log level, default is `info`.
Level string `json:",default=info,options=[debug,info,error,severe]"`
// MaxContentLength represents the max content bytes, default is no limit.
MaxContentLength uint32 `json:",optional"`
// Compress represents whether to compress the log file, default is `false`.
Compress bool `json:",optional"`
// Stdout represents whether to log statistics, default is `true`.
Stat bool `json:",default=true"`
// KeepDays represents how many days the log files will be kept. Default to keep all files.
// Only take effect when Mode is `file` or `volume`, both work when Rotation is `daily` or `size`.
KeepDays int `json:",optional"`
// StackCooldownMillis represents the cooldown time for stack logging, default is 100ms.
StackCooldownMillis int `json:",default=100"`
// MaxBackups represents how many backup log files will be kept. 0 means all files will be kept forever. // MaxBackups represents how many backup log files will be kept. 0 means all files will be kept forever.
// Only take effect when RotationRuleType is `size`. // Only take effect when RotationRuleType is `size`.
// Even thougth `MaxBackups` sets 0, log files will still be removed // Even thougth `MaxBackups` sets 0, log files will still be removed

View File

@@ -25,7 +25,7 @@ func TestAddGlobalFields(t *testing.T) {
AddGlobalFields(Field("a", "1"), Field("b", "2")) AddGlobalFields(Field("a", "1"), Field("b", "2"))
AddGlobalFields(Field("c", "3")) AddGlobalFields(Field("c", "3"))
Info("world") Info("world")
var m map[string]interface{} var m map[string]any
assert.NoError(t, json.Unmarshal(buf.Bytes(), &m)) assert.NoError(t, json.Unmarshal(buf.Bytes(), &m))
assert.Equal(t, "1", m["a"]) assert.Equal(t, "1", m["a"])
assert.Equal(t, "2", m["b"]) assert.Equal(t, "2", m["b"])

View File

@@ -13,14 +13,14 @@ func NewLessLogger(milliseconds int) *LessLogger {
} }
// Error logs v into error log or discard it if more than once in the given duration. // Error logs v into error log or discard it if more than once in the given duration.
func (logger *LessLogger) Error(v ...interface{}) { func (logger *LessLogger) Error(v ...any) {
logger.logOrDiscard(func() { logger.logOrDiscard(func() {
Error(v...) Error(v...)
}) })
} }
// Errorf logs v with format into error log or discard it if more than once in the given duration. // Errorf logs v with format into error log or discard it if more than once in the given duration.
func (logger *LessLogger) Errorf(format string, v ...interface{}) { func (logger *LessLogger) Errorf(format string, v ...any) {
logger.logOrDiscard(func() { logger.logOrDiscard(func() {
Errorf(format, v...) Errorf(format, v...)
}) })

View File

@@ -8,35 +8,35 @@ import (
// A Logger represents a logger. // A Logger represents a logger.
type Logger interface { type Logger interface {
// Debug logs a message at info level. // Debug logs a message at info level.
Debug(...interface{}) Debug(...any)
// Debugf logs a message at info level. // Debugf logs a message at info level.
Debugf(string, ...interface{}) Debugf(string, ...any)
// Debugv logs a message at info level. // Debugv logs a message at info level.
Debugv(interface{}) Debugv(any)
// Debugw logs a message at info level. // Debugw logs a message at info level.
Debugw(string, ...LogField) Debugw(string, ...LogField)
// Error logs a message at error level. // Error logs a message at error level.
Error(...interface{}) Error(...any)
// Errorf logs a message at error level. // Errorf logs a message at error level.
Errorf(string, ...interface{}) Errorf(string, ...any)
// Errorv logs a message at error level. // Errorv logs a message at error level.
Errorv(interface{}) Errorv(any)
// Errorw logs a message at error level. // Errorw logs a message at error level.
Errorw(string, ...LogField) Errorw(string, ...LogField)
// Info logs a message at info level. // Info logs a message at info level.
Info(...interface{}) Info(...any)
// Infof logs a message at info level. // Infof logs a message at info level.
Infof(string, ...interface{}) Infof(string, ...any)
// Infov logs a message at info level. // Infov logs a message at info level.
Infov(interface{}) Infov(any)
// Infow logs a message at info level. // Infow logs a message at info level.
Infow(string, ...LogField) Infow(string, ...LogField)
// Slow logs a message at slow level. // Slow logs a message at slow level.
Slow(...interface{}) Slow(...any)
// Slowf logs a message at slow level. // Slowf logs a message at slow level.
Slowf(string, ...interface{}) Slowf(string, ...any)
// Slowv logs a message at slow level. // Slowv logs a message at slow level.
Slowv(interface{}) Slowv(any)
// Sloww logs a message at slow level. // Sloww logs a message at slow level.
Sloww(string, ...LogField) Sloww(string, ...LogField)
// WithCallerSkip returns a new logger with the given caller skip. // WithCallerSkip returns a new logger with the given caller skip.

View File

@@ -34,13 +34,13 @@ type (
// LogField is a key-value pair that will be added to the log entry. // LogField is a key-value pair that will be added to the log entry.
LogField struct { LogField struct {
Key string Key string
Value interface{} Value any
} }
// LogOption defines the method to customize the logging. // LogOption defines the method to customize the logging.
LogOption func(options *logOptions) LogOption func(options *logOptions)
logEntry map[string]interface{} logEntry map[string]any
logOptions struct { logOptions struct {
gzipEnabled bool gzipEnabled bool
@@ -67,17 +67,17 @@ func Close() error {
} }
// Debug writes v into access log. // Debug writes v into access log.
func Debug(v ...interface{}) { func Debug(v ...any) {
writeDebug(fmt.Sprint(v...)) writeDebug(fmt.Sprint(v...))
} }
// Debugf writes v with format into access log. // Debugf writes v with format into access log.
func Debugf(format string, v ...interface{}) { func Debugf(format string, v ...any) {
writeDebug(fmt.Sprintf(format, v...)) writeDebug(fmt.Sprintf(format, v...))
} }
// Debugv writes v into access log with json content. // Debugv writes v into access log with json content.
func Debugv(v interface{}) { func Debugv(v any) {
writeDebug(v) writeDebug(v)
} }
@@ -98,30 +98,30 @@ func DisableStat() {
} }
// Error writes v into error log. // Error writes v into error log.
func Error(v ...interface{}) { func Error(v ...any) {
writeError(fmt.Sprint(v...)) writeError(fmt.Sprint(v...))
} }
// Errorf writes v with format into error log. // Errorf writes v with format into error log.
func Errorf(format string, v ...interface{}) { func Errorf(format string, v ...any) {
writeError(fmt.Errorf(format, v...).Error()) writeError(fmt.Errorf(format, v...).Error())
} }
// ErrorStack writes v along with call stack into error log. // ErrorStack writes v along with call stack into error log.
func ErrorStack(v ...interface{}) { func ErrorStack(v ...any) {
// there is newline in stack string // there is newline in stack string
writeStack(fmt.Sprint(v...)) writeStack(fmt.Sprint(v...))
} }
// ErrorStackf writes v along with call stack in format into error log. // ErrorStackf writes v along with call stack in format into error log.
func ErrorStackf(format string, v ...interface{}) { func ErrorStackf(format string, v ...any) {
// there is newline in stack string // there is newline in stack string
writeStack(fmt.Sprintf(format, v...)) writeStack(fmt.Sprintf(format, v...))
} }
// Errorv writes v into error log with json content. // Errorv writes v into error log with json content.
// No call stack attached, because not elegant to pack the messages. // No call stack attached, because not elegant to pack the messages.
func Errorv(v interface{}) { func Errorv(v any) {
writeError(v) writeError(v)
} }
@@ -131,7 +131,7 @@ func Errorw(msg string, fields ...LogField) {
} }
// Field returns a LogField for the given key and value. // Field returns a LogField for the given key and value.
func Field(key string, value interface{}) LogField { func Field(key string, value any) LogField {
switch val := value.(type) { switch val := value.(type) {
case error: case error:
return LogField{Key: key, Value: val.Error()} return LogField{Key: key, Value: val.Error()}
@@ -169,17 +169,17 @@ func Field(key string, value interface{}) LogField {
} }
// Info writes v into access log. // Info writes v into access log.
func Info(v ...interface{}) { func Info(v ...any) {
writeInfo(fmt.Sprint(v...)) writeInfo(fmt.Sprint(v...))
} }
// Infof writes v with format into access log. // Infof writes v with format into access log.
func Infof(format string, v ...interface{}) { func Infof(format string, v ...any) {
writeInfo(fmt.Sprintf(format, v...)) writeInfo(fmt.Sprintf(format, v...))
} }
// Infov writes v into access log with json content. // Infov writes v into access log with json content.
func Infov(v interface{}) { func Infov(v any) {
writeInfo(v) writeInfo(v)
} }
@@ -263,27 +263,27 @@ func SetUp(c LogConf) (err error) {
} }
// Severe writes v into severe log. // Severe writes v into severe log.
func Severe(v ...interface{}) { func Severe(v ...any) {
writeSevere(fmt.Sprint(v...)) writeSevere(fmt.Sprint(v...))
} }
// Severef writes v with format into severe log. // Severef writes v with format into severe log.
func Severef(format string, v ...interface{}) { func Severef(format string, v ...any) {
writeSevere(fmt.Sprintf(format, v...)) writeSevere(fmt.Sprintf(format, v...))
} }
// Slow writes v into slow log. // Slow writes v into slow log.
func Slow(v ...interface{}) { func Slow(v ...any) {
writeSlow(fmt.Sprint(v...)) writeSlow(fmt.Sprint(v...))
} }
// Slowf writes v with format into slow log. // Slowf writes v with format into slow log.
func Slowf(format string, v ...interface{}) { func Slowf(format string, v ...any) {
writeSlow(fmt.Sprintf(format, v...)) writeSlow(fmt.Sprintf(format, v...))
} }
// Slowv writes v into slow log with json content. // Slowv writes v into slow log with json content.
func Slowv(v interface{}) { func Slowv(v any) {
writeSlow(v) writeSlow(v)
} }
@@ -293,12 +293,12 @@ func Sloww(msg string, fields ...LogField) {
} }
// Stat writes v into stat log. // Stat writes v into stat log.
func Stat(v ...interface{}) { func Stat(v ...any) {
writeStat(fmt.Sprint(v...)) writeStat(fmt.Sprint(v...))
} }
// Statf writes v with format into stat log. // Statf writes v with format into stat log.
func Statf(format string, v ...interface{}) { func Statf(format string, v ...any) {
writeStat(fmt.Sprintf(format, v...)) writeStat(fmt.Sprintf(format, v...))
} }
@@ -422,19 +422,19 @@ func shallLogStat() bool {
return atomic.LoadUint32(&disableStat) == 0 return atomic.LoadUint32(&disableStat) == 0
} }
func writeDebug(val interface{}, fields ...LogField) { func writeDebug(val any, fields ...LogField) {
if shallLog(DebugLevel) { if shallLog(DebugLevel) {
getWriter().Debug(val, addCaller(fields...)...) getWriter().Debug(val, addCaller(fields...)...)
} }
} }
func writeError(val interface{}, fields ...LogField) { func writeError(val any, fields ...LogField) {
if shallLog(ErrorLevel) { if shallLog(ErrorLevel) {
getWriter().Error(val, addCaller(fields...)...) getWriter().Error(val, addCaller(fields...)...)
} }
} }
func writeInfo(val interface{}, fields ...LogField) { func writeInfo(val any, fields ...LogField) {
if shallLog(InfoLevel) { if shallLog(InfoLevel) {
getWriter().Info(val, addCaller(fields...)...) getWriter().Info(val, addCaller(fields...)...)
} }
@@ -446,7 +446,7 @@ func writeSevere(msg string) {
} }
} }
func writeSlow(val interface{}, fields ...LogField) { func writeSlow(val any, fields ...LogField) {
if shallLog(ErrorLevel) { if shallLog(ErrorLevel) {
getWriter().Slow(val, addCaller(fields...)...) getWriter().Slow(val, addCaller(fields...)...)
} }

View File

@@ -29,49 +29,49 @@ type mockWriter struct {
builder strings.Builder builder strings.Builder
} }
func (mw *mockWriter) Alert(v interface{}) { func (mw *mockWriter) Alert(v any) {
mw.lock.Lock() mw.lock.Lock()
defer mw.lock.Unlock() defer mw.lock.Unlock()
output(&mw.builder, levelAlert, v) output(&mw.builder, levelAlert, v)
} }
func (mw *mockWriter) Debug(v interface{}, fields ...LogField) { func (mw *mockWriter) Debug(v any, fields ...LogField) {
mw.lock.Lock() mw.lock.Lock()
defer mw.lock.Unlock() defer mw.lock.Unlock()
output(&mw.builder, levelDebug, v, fields...) output(&mw.builder, levelDebug, v, fields...)
} }
func (mw *mockWriter) Error(v interface{}, fields ...LogField) { func (mw *mockWriter) Error(v any, fields ...LogField) {
mw.lock.Lock() mw.lock.Lock()
defer mw.lock.Unlock() defer mw.lock.Unlock()
output(&mw.builder, levelError, v, fields...) output(&mw.builder, levelError, v, fields...)
} }
func (mw *mockWriter) Info(v interface{}, fields ...LogField) { func (mw *mockWriter) Info(v any, fields ...LogField) {
mw.lock.Lock() mw.lock.Lock()
defer mw.lock.Unlock() defer mw.lock.Unlock()
output(&mw.builder, levelInfo, v, fields...) output(&mw.builder, levelInfo, v, fields...)
} }
func (mw *mockWriter) Severe(v interface{}) { func (mw *mockWriter) Severe(v any) {
mw.lock.Lock() mw.lock.Lock()
defer mw.lock.Unlock() defer mw.lock.Unlock()
output(&mw.builder, levelSevere, v) output(&mw.builder, levelSevere, v)
} }
func (mw *mockWriter) Slow(v interface{}, fields ...LogField) { func (mw *mockWriter) Slow(v any, fields ...LogField) {
mw.lock.Lock() mw.lock.Lock()
defer mw.lock.Unlock() defer mw.lock.Unlock()
output(&mw.builder, levelSlow, v, fields...) output(&mw.builder, levelSlow, v, fields...)
} }
func (mw *mockWriter) Stack(v interface{}) { func (mw *mockWriter) Stack(v any) {
mw.lock.Lock() mw.lock.Lock()
defer mw.lock.Unlock() defer mw.lock.Unlock()
output(&mw.builder, levelError, v) output(&mw.builder, levelError, v)
} }
func (mw *mockWriter) Stat(v interface{}, fields ...LogField) { func (mw *mockWriter) Stat(v any, fields ...LogField) {
mw.lock.Lock() mw.lock.Lock()
defer mw.lock.Unlock() defer mw.lock.Unlock()
output(&mw.builder, levelStat, v, fields...) output(&mw.builder, levelStat, v, fields...)
@@ -103,41 +103,41 @@ func TestField(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
f LogField f LogField
want map[string]interface{} want map[string]any
}{ }{
{ {
name: "error", name: "error",
f: Field("foo", errors.New("bar")), f: Field("foo", errors.New("bar")),
want: map[string]interface{}{ want: map[string]any{
"foo": "bar", "foo": "bar",
}, },
}, },
{ {
name: "errors", name: "errors",
f: Field("foo", []error{errors.New("bar"), errors.New("baz")}), f: Field("foo", []error{errors.New("bar"), errors.New("baz")}),
want: map[string]interface{}{ want: map[string]any{
"foo": []interface{}{"bar", "baz"}, "foo": []any{"bar", "baz"},
}, },
}, },
{ {
name: "strings", name: "strings",
f: Field("foo", []string{"bar", "baz"}), f: Field("foo", []string{"bar", "baz"}),
want: map[string]interface{}{ want: map[string]any{
"foo": []interface{}{"bar", "baz"}, "foo": []any{"bar", "baz"},
}, },
}, },
{ {
name: "duration", name: "duration",
f: Field("foo", time.Second), f: Field("foo", time.Second),
want: map[string]interface{}{ want: map[string]any{
"foo": "1s", "foo": "1s",
}, },
}, },
{ {
name: "durations", name: "durations",
f: Field("foo", []time.Duration{time.Second, 2 * time.Second}), f: Field("foo", []time.Duration{time.Second, 2 * time.Second}),
want: map[string]interface{}{ want: map[string]any{
"foo": []interface{}{"1s", "2s"}, "foo": []any{"1s", "2s"},
}, },
}, },
{ {
@@ -146,22 +146,22 @@ func TestField(t *testing.T) {
time.Date(2020, time.January, 1, 0, 0, 0, 0, time.UTC), time.Date(2020, time.January, 1, 0, 0, 0, 0, time.UTC),
time.Date(2020, time.January, 2, 0, 0, 0, 0, time.UTC), time.Date(2020, time.January, 2, 0, 0, 0, 0, time.UTC),
}), }),
want: map[string]interface{}{ want: map[string]any{
"foo": []interface{}{"2020-01-01 00:00:00 +0000 UTC", "2020-01-02 00:00:00 +0000 UTC"}, "foo": []any{"2020-01-01 00:00:00 +0000 UTC", "2020-01-02 00:00:00 +0000 UTC"},
}, },
}, },
{ {
name: "stringer", name: "stringer",
f: Field("foo", ValStringer{val: "bar"}), f: Field("foo", ValStringer{val: "bar"}),
want: map[string]interface{}{ want: map[string]any{
"foo": "bar", "foo": "bar",
}, },
}, },
{ {
name: "stringers", name: "stringers",
f: Field("foo", []fmt.Stringer{ValStringer{val: "bar"}, ValStringer{val: "baz"}}), f: Field("foo", []fmt.Stringer{ValStringer{val: "bar"}, ValStringer{val: "baz"}}),
want: map[string]interface{}{ want: map[string]any{
"foo": []interface{}{"bar", "baz"}, "foo": []any{"bar", "baz"},
}, },
}, },
} }
@@ -213,7 +213,7 @@ func TestStructedLogAlert(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelAlert, w, func(v ...interface{}) { doTestStructedLog(t, levelAlert, w, func(v ...any) {
Alert(fmt.Sprint(v...)) Alert(fmt.Sprint(v...))
}) })
} }
@@ -223,7 +223,7 @@ func TestStructedLogDebug(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelDebug, w, func(v ...interface{}) { doTestStructedLog(t, levelDebug, w, func(v ...any) {
Debug(v...) Debug(v...)
}) })
} }
@@ -233,7 +233,7 @@ func TestStructedLogDebugf(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelDebug, w, func(v ...interface{}) { doTestStructedLog(t, levelDebug, w, func(v ...any) {
Debugf(fmt.Sprint(v...)) Debugf(fmt.Sprint(v...))
}) })
} }
@@ -243,7 +243,7 @@ func TestStructedLogDebugv(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelDebug, w, func(v ...interface{}) { doTestStructedLog(t, levelDebug, w, func(v ...any) {
Debugv(fmt.Sprint(v...)) Debugv(fmt.Sprint(v...))
}) })
} }
@@ -253,7 +253,7 @@ func TestStructedLogDebugw(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelDebug, w, func(v ...interface{}) { doTestStructedLog(t, levelDebug, w, func(v ...any) {
Debugw(fmt.Sprint(v...), Field("foo", time.Second)) Debugw(fmt.Sprint(v...), Field("foo", time.Second))
}) })
} }
@@ -263,7 +263,7 @@ func TestStructedLogError(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelError, w, func(v ...interface{}) { doTestStructedLog(t, levelError, w, func(v ...any) {
Error(v...) Error(v...)
}) })
} }
@@ -273,7 +273,7 @@ func TestStructedLogErrorf(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelError, w, func(v ...interface{}) { doTestStructedLog(t, levelError, w, func(v ...any) {
Errorf("%s", fmt.Sprint(v...)) Errorf("%s", fmt.Sprint(v...))
}) })
} }
@@ -283,7 +283,7 @@ func TestStructedLogErrorv(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelError, w, func(v ...interface{}) { doTestStructedLog(t, levelError, w, func(v ...any) {
Errorv(fmt.Sprint(v...)) Errorv(fmt.Sprint(v...))
}) })
} }
@@ -293,7 +293,7 @@ func TestStructedLogErrorw(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelError, w, func(v ...interface{}) { doTestStructedLog(t, levelError, w, func(v ...any) {
Errorw(fmt.Sprint(v...), Field("foo", "bar")) Errorw(fmt.Sprint(v...), Field("foo", "bar"))
}) })
} }
@@ -303,7 +303,7 @@ func TestStructedLogInfo(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelInfo, w, func(v ...interface{}) { doTestStructedLog(t, levelInfo, w, func(v ...any) {
Info(v...) Info(v...)
}) })
} }
@@ -313,7 +313,7 @@ func TestStructedLogInfof(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelInfo, w, func(v ...interface{}) { doTestStructedLog(t, levelInfo, w, func(v ...any) {
Infof("%s", fmt.Sprint(v...)) Infof("%s", fmt.Sprint(v...))
}) })
} }
@@ -323,7 +323,7 @@ func TestStructedLogInfov(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelInfo, w, func(v ...interface{}) { doTestStructedLog(t, levelInfo, w, func(v ...any) {
Infov(fmt.Sprint(v...)) Infov(fmt.Sprint(v...))
}) })
} }
@@ -333,7 +333,7 @@ func TestStructedLogInfow(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelInfo, w, func(v ...interface{}) { doTestStructedLog(t, levelInfo, w, func(v ...any) {
Infow(fmt.Sprint(v...), Field("foo", "bar")) Infow(fmt.Sprint(v...), Field("foo", "bar"))
}) })
} }
@@ -343,7 +343,7 @@ func TestStructedLogInfoConsoleAny(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLogConsole(t, w, func(v ...interface{}) { doTestStructedLogConsole(t, w, func(v ...any) {
old := atomic.LoadUint32(&encoding) old := atomic.LoadUint32(&encoding)
atomic.StoreUint32(&encoding, plainEncodingType) atomic.StoreUint32(&encoding, plainEncodingType)
defer func() { defer func() {
@@ -359,7 +359,7 @@ func TestStructedLogInfoConsoleAnyString(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLogConsole(t, w, func(v ...interface{}) { doTestStructedLogConsole(t, w, func(v ...any) {
old := atomic.LoadUint32(&encoding) old := atomic.LoadUint32(&encoding)
atomic.StoreUint32(&encoding, plainEncodingType) atomic.StoreUint32(&encoding, plainEncodingType)
defer func() { defer func() {
@@ -375,7 +375,7 @@ func TestStructedLogInfoConsoleAnyError(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLogConsole(t, w, func(v ...interface{}) { doTestStructedLogConsole(t, w, func(v ...any) {
old := atomic.LoadUint32(&encoding) old := atomic.LoadUint32(&encoding)
atomic.StoreUint32(&encoding, plainEncodingType) atomic.StoreUint32(&encoding, plainEncodingType)
defer func() { defer func() {
@@ -391,7 +391,7 @@ func TestStructedLogInfoConsoleAnyStringer(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLogConsole(t, w, func(v ...interface{}) { doTestStructedLogConsole(t, w, func(v ...any) {
old := atomic.LoadUint32(&encoding) old := atomic.LoadUint32(&encoding)
atomic.StoreUint32(&encoding, plainEncodingType) atomic.StoreUint32(&encoding, plainEncodingType)
defer func() { defer func() {
@@ -409,7 +409,7 @@ func TestStructedLogInfoConsoleText(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLogConsole(t, w, func(v ...interface{}) { doTestStructedLogConsole(t, w, func(v ...any) {
old := atomic.LoadUint32(&encoding) old := atomic.LoadUint32(&encoding)
atomic.StoreUint32(&encoding, plainEncodingType) atomic.StoreUint32(&encoding, plainEncodingType)
defer func() { defer func() {
@@ -425,7 +425,7 @@ func TestStructedLogSlow(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelSlow, w, func(v ...interface{}) { doTestStructedLog(t, levelSlow, w, func(v ...any) {
Slow(v...) Slow(v...)
}) })
} }
@@ -435,7 +435,7 @@ func TestStructedLogSlowf(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelSlow, w, func(v ...interface{}) { doTestStructedLog(t, levelSlow, w, func(v ...any) {
Slowf(fmt.Sprint(v...)) Slowf(fmt.Sprint(v...))
}) })
} }
@@ -445,7 +445,7 @@ func TestStructedLogSlowv(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelSlow, w, func(v ...interface{}) { doTestStructedLog(t, levelSlow, w, func(v ...any) {
Slowv(fmt.Sprint(v...)) Slowv(fmt.Sprint(v...))
}) })
} }
@@ -455,7 +455,7 @@ func TestStructedLogSloww(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelSlow, w, func(v ...interface{}) { doTestStructedLog(t, levelSlow, w, func(v ...any) {
Sloww(fmt.Sprint(v...), Field("foo", time.Second)) Sloww(fmt.Sprint(v...), Field("foo", time.Second))
}) })
} }
@@ -465,7 +465,7 @@ func TestStructedLogStat(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelStat, w, func(v ...interface{}) { doTestStructedLog(t, levelStat, w, func(v ...any) {
Stat(v...) Stat(v...)
}) })
} }
@@ -475,7 +475,7 @@ func TestStructedLogStatf(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelStat, w, func(v ...interface{}) { doTestStructedLog(t, levelStat, w, func(v ...any) {
Statf(fmt.Sprint(v...)) Statf(fmt.Sprint(v...))
}) })
} }
@@ -485,7 +485,7 @@ func TestStructedLogSevere(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelSevere, w, func(v ...interface{}) { doTestStructedLog(t, levelSevere, w, func(v ...any) {
Severe(v...) Severe(v...)
}) })
} }
@@ -495,7 +495,7 @@ func TestStructedLogSeveref(t *testing.T) {
old := writer.Swap(w) old := writer.Swap(w)
defer writer.Store(old) defer writer.Store(old)
doTestStructedLog(t, levelSevere, w, func(v ...interface{}) { doTestStructedLog(t, levelSevere, w, func(v ...any) {
Severef(fmt.Sprint(v...)) Severef(fmt.Sprint(v...))
}) })
} }
@@ -507,7 +507,7 @@ func TestStructedLogWithDuration(t *testing.T) {
defer writer.Store(old) defer writer.Store(old)
WithDuration(time.Second).Info(message) WithDuration(time.Second).Info(message)
var entry map[string]interface{} var entry map[string]any
if err := json.Unmarshal([]byte(w.String()), &entry); err != nil { if err := json.Unmarshal([]byte(w.String()), &entry); err != nil {
t.Error(err) t.Error(err)
} }
@@ -767,11 +767,11 @@ func put(b []byte) {
} }
} }
func doTestStructedLog(t *testing.T, level string, w *mockWriter, write func(...interface{})) { func doTestStructedLog(t *testing.T, level string, w *mockWriter, write func(...any)) {
const message = "hello there" const message = "hello there"
write(message) write(message)
var entry map[string]interface{} var entry map[string]any
if err := json.Unmarshal([]byte(w.String()), &entry); err != nil { if err := json.Unmarshal([]byte(w.String()), &entry); err != nil {
t.Error(err) t.Error(err)
} }
@@ -782,7 +782,7 @@ func doTestStructedLog(t *testing.T, level string, w *mockWriter, write func(...
assert.True(t, strings.Contains(val.(string), message)) assert.True(t, strings.Contains(val.(string), message))
} }
func doTestStructedLogConsole(t *testing.T, w *mockWriter, write func(...interface{})) { func doTestStructedLogConsole(t *testing.T, w *mockWriter, write func(...any)) {
const message = "hello there" const message = "hello there"
write(message) write(message)
assert.True(t, strings.Contains(w.String(), message)) assert.True(t, strings.Contains(w.String(), message))
@@ -822,8 +822,8 @@ func (v ValStringer) String() string {
return v.val return v.val
} }
func validateFields(t *testing.T, content string, fields map[string]interface{}) { func validateFields(t *testing.T, content string, fields map[string]any) {
var m map[string]interface{} var m map[string]any
if err := json.Unmarshal([]byte(content), &m); err != nil { if err := json.Unmarshal([]byte(content), &m); err != nil {
t.Error(err) t.Error(err)
} }

View File

@@ -52,27 +52,27 @@ type LogConf struct {
```go ```go
type Logger interface { type Logger interface {
// Error logs a message at error level. // Error logs a message at error level.
Error(...interface{}) Error(...any)
// Errorf logs a message at error level. // Errorf logs a message at error level.
Errorf(string, ...interface{}) Errorf(string, ...any)
// Errorv logs a message at error level. // Errorv logs a message at error level.
Errorv(interface{}) Errorv(any)
// Errorw logs a message at error level. // Errorw logs a message at error level.
Errorw(string, ...LogField) Errorw(string, ...LogField)
// Info logs a message at info level. // Info logs a message at info level.
Info(...interface{}) Info(...any)
// Infof logs a message at info level. // Infof logs a message at info level.
Infof(string, ...interface{}) Infof(string, ...any)
// Infov logs a message at info level. // Infov logs a message at info level.
Infov(interface{}) Infov(any)
// Infow logs a message at info level. // Infow logs a message at info level.
Infow(string, ...LogField) Infow(string, ...LogField)
// Slow logs a message at slow level. // Slow logs a message at slow level.
Slow(...interface{}) Slow(...any)
// Slowf logs a message at slow level. // Slowf logs a message at slow level.
Slowf(string, ...interface{}) Slowf(string, ...any)
// Slowv logs a message at slow level. // Slowv logs a message at slow level.
Slowv(interface{}) Slowv(any)
// Sloww logs a message at slow level. // Sloww logs a message at slow level.
Sloww(string, ...LogField) Sloww(string, ...LogField)
// WithContext returns a new logger with the given context. // WithContext returns a new logger with the given context.
@@ -165,7 +165,7 @@ func NewSensitiveLogger(writer logx.Writer) *SensitiveLogger {
} }
} }
func (l *SensitiveLogger) Info(msg interface{}, fields ...logx.LogField) { func (l *SensitiveLogger) Info(msg any, fields ...logx.LogField) {
if m, ok := msg.(Message); ok { if m, ok := msg.(Message); ok {
l.Writer.Info(Message{ l.Writer.Info(Message{
Name: m.Name, Name: m.Name,

View File

@@ -51,27 +51,27 @@ type LogConf struct {
```go ```go
type Logger interface { type Logger interface {
// Error logs a message at error level. // Error logs a message at error level.
Error(...interface{}) Error(...any)
// Errorf logs a message at error level. // Errorf logs a message at error level.
Errorf(string, ...interface{}) Errorf(string, ...any)
// Errorv logs a message at error level. // Errorv logs a message at error level.
Errorv(interface{}) Errorv(any)
// Errorw logs a message at error level. // Errorw logs a message at error level.
Errorw(string, ...LogField) Errorw(string, ...LogField)
// Info logs a message at info level. // Info logs a message at info level.
Info(...interface{}) Info(...any)
// Infof logs a message at info level. // Infof logs a message at info level.
Infof(string, ...interface{}) Infof(string, ...any)
// Infov logs a message at info level. // Infov logs a message at info level.
Infov(interface{}) Infov(any)
// Infow logs a message at info level. // Infow logs a message at info level.
Infow(string, ...LogField) Infow(string, ...LogField)
// Slow logs a message at slow level. // Slow logs a message at slow level.
Slow(...interface{}) Slow(...any)
// Slowf logs a message at slow level. // Slowf logs a message at slow level.
Slowf(string, ...interface{}) Slowf(string, ...any)
// Slowv logs a message at slow level. // Slowv logs a message at slow level.
Slowv(interface{}) Slowv(any)
// Sloww logs a message at slow level. // Sloww logs a message at slow level.
Sloww(string, ...LogField) Sloww(string, ...LogField)
// WithContext returns a new logger with the given context. // WithContext returns a new logger with the given context.
@@ -164,7 +164,7 @@ func NewSensitiveLogger(writer logx.Writer) *SensitiveLogger {
} }
} }
func (l *SensitiveLogger) Info(msg interface{}, fields ...logx.LogField) { func (l *SensitiveLogger) Info(msg any, fields ...logx.LogField) {
if m, ok := msg.(Message); ok { if m, ok := msg.(Message); ok {
l.Writer.Info(Message{ l.Writer.Info(Message{
Name: m.Name, Name: m.Name,

View File

@@ -40,15 +40,15 @@ type richLogger struct {
fields []LogField fields []LogField
} }
func (l *richLogger) Debug(v ...interface{}) { func (l *richLogger) Debug(v ...any) {
l.debug(fmt.Sprint(v...)) l.debug(fmt.Sprint(v...))
} }
func (l *richLogger) Debugf(format string, v ...interface{}) { func (l *richLogger) Debugf(format string, v ...any) {
l.debug(fmt.Sprintf(format, v...)) l.debug(fmt.Sprintf(format, v...))
} }
func (l *richLogger) Debugv(v interface{}) { func (l *richLogger) Debugv(v any) {
l.debug(v) l.debug(v)
} }
@@ -56,15 +56,15 @@ func (l *richLogger) Debugw(msg string, fields ...LogField) {
l.debug(msg, fields...) l.debug(msg, fields...)
} }
func (l *richLogger) Error(v ...interface{}) { func (l *richLogger) Error(v ...any) {
l.err(fmt.Sprint(v...)) l.err(fmt.Sprint(v...))
} }
func (l *richLogger) Errorf(format string, v ...interface{}) { func (l *richLogger) Errorf(format string, v ...any) {
l.err(fmt.Sprintf(format, v...)) l.err(fmt.Sprintf(format, v...))
} }
func (l *richLogger) Errorv(v interface{}) { func (l *richLogger) Errorv(v any) {
l.err(fmt.Sprint(v)) l.err(fmt.Sprint(v))
} }
@@ -72,15 +72,15 @@ func (l *richLogger) Errorw(msg string, fields ...LogField) {
l.err(msg, fields...) l.err(msg, fields...)
} }
func (l *richLogger) Info(v ...interface{}) { func (l *richLogger) Info(v ...any) {
l.info(fmt.Sprint(v...)) l.info(fmt.Sprint(v...))
} }
func (l *richLogger) Infof(format string, v ...interface{}) { func (l *richLogger) Infof(format string, v ...any) {
l.info(fmt.Sprintf(format, v...)) l.info(fmt.Sprintf(format, v...))
} }
func (l *richLogger) Infov(v interface{}) { func (l *richLogger) Infov(v any) {
l.info(v) l.info(v)
} }
@@ -88,15 +88,15 @@ func (l *richLogger) Infow(msg string, fields ...LogField) {
l.info(msg, fields...) l.info(msg, fields...)
} }
func (l *richLogger) Slow(v ...interface{}) { func (l *richLogger) Slow(v ...any) {
l.slow(fmt.Sprint(v...)) l.slow(fmt.Sprint(v...))
} }
func (l *richLogger) Slowf(format string, v ...interface{}) { func (l *richLogger) Slowf(format string, v ...any) {
l.slow(fmt.Sprintf(format, v...)) l.slow(fmt.Sprintf(format, v...))
} }
func (l *richLogger) Slowv(v interface{}) { func (l *richLogger) Slowv(v any) {
l.slow(v) l.slow(v)
} }
@@ -156,25 +156,25 @@ func (l *richLogger) buildFields(fields ...LogField) []LogField {
return fields return fields
} }
func (l *richLogger) debug(v interface{}, fields ...LogField) { func (l *richLogger) debug(v any, fields ...LogField) {
if shallLog(DebugLevel) { if shallLog(DebugLevel) {
getWriter().Debug(v, l.buildFields(fields...)...) getWriter().Debug(v, l.buildFields(fields...)...)
} }
} }
func (l *richLogger) err(v interface{}, fields ...LogField) { func (l *richLogger) err(v any, fields ...LogField) {
if shallLog(ErrorLevel) { if shallLog(ErrorLevel) {
getWriter().Error(v, l.buildFields(fields...)...) getWriter().Error(v, l.buildFields(fields...)...)
} }
} }
func (l *richLogger) info(v interface{}, fields ...LogField) { func (l *richLogger) info(v any, fields ...LogField) {
if shallLog(InfoLevel) { if shallLog(InfoLevel) {
getWriter().Info(v, l.buildFields(fields...)...) getWriter().Info(v, l.buildFields(fields...)...)
} }
} }
func (l *richLogger) slow(v interface{}, fields ...LogField) { func (l *richLogger) slow(v any, fields ...LogField) {
if shallLog(ErrorLevel) { if shallLog(ErrorLevel) {
getWriter().Slow(v, l.buildFields(fields...)...) getWriter().Slow(v, l.buildFields(fields...)...)
} }

View File

@@ -9,6 +9,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/fs" "github.com/zeromicro/go-zero/core/fs"
"github.com/zeromicro/go-zero/core/stringx"
) )
func TestDailyRotateRuleMarkRotated(t *testing.T) { func TestDailyRotateRuleMarkRotated(t *testing.T) {
@@ -232,6 +233,23 @@ func TestRotateLoggerWithSizeLimitRotateRuleMayCompressFileTrue(t *testing.T) {
assert.NotNil(t, err) assert.NotNil(t, err)
} }
func TestRotateLoggerWithSizeLimitRotateRuleMayCompressFileFailed(t *testing.T) {
old := os.Stdout
os.Stdout = os.NewFile(0, os.DevNull)
defer func() {
os.Stdout = old
}()
filename := stringx.RandId()
logger, err := NewLogger(filename, new(SizeLimitRotateRule), true)
defer os.Remove(filename)
if assert.NoError(t, err) {
assert.NotPanics(t, func() {
logger.maybeCompressFile(stringx.RandId())
})
}
}
func TestRotateLoggerWithSizeLimitRotateRuleRotate(t *testing.T) { func TestRotateLoggerWithSizeLimitRotateRuleRotate(t *testing.T) {
filename, err := fs.TempFilenameWithText("foo") filename, err := fs.TempFilenameWithText("foo")
assert.Nil(t, err) assert.Nil(t, err)

View File

@@ -42,7 +42,7 @@ func captureOutput(f func()) string {
} }
func getContent(jsonStr string) string { func getContent(jsonStr string) string {
var entry map[string]interface{} var entry map[string]any
json.Unmarshal([]byte(jsonStr), &entry) json.Unmarshal([]byte(jsonStr), &entry)
val, ok := entry[contentKey] val, ok := entry[contentKey]

View File

@@ -16,15 +16,15 @@ import (
type ( type (
Writer interface { Writer interface {
Alert(v interface{}) Alert(v any)
Close() error Close() error
Debug(v interface{}, fields ...LogField) Debug(v any, fields ...LogField)
Error(v interface{}, fields ...LogField) Error(v any, fields ...LogField)
Info(v interface{}, fields ...LogField) Info(v any, fields ...LogField)
Severe(v interface{}) Severe(v any)
Slow(v interface{}, fields ...LogField) Slow(v any, fields ...LogField)
Stack(v interface{}) Stack(v any)
Stat(v interface{}, fields ...LogField) Stat(v any, fields ...LogField)
} }
atomicWriter struct { atomicWriter struct {
@@ -171,7 +171,7 @@ func newFileWriter(c LogConf) (Writer, error) {
}, nil }, nil
} }
func (w *concreteWriter) Alert(v interface{}) { func (w *concreteWriter) Alert(v any) {
output(w.errorLog, levelAlert, v) output(w.errorLog, levelAlert, v)
} }
@@ -195,62 +195,62 @@ func (w *concreteWriter) Close() error {
return w.statLog.Close() return w.statLog.Close()
} }
func (w *concreteWriter) Debug(v interface{}, fields ...LogField) { func (w *concreteWriter) Debug(v any, fields ...LogField) {
output(w.infoLog, levelDebug, v, fields...) output(w.infoLog, levelDebug, v, fields...)
} }
func (w *concreteWriter) Error(v interface{}, fields ...LogField) { func (w *concreteWriter) Error(v any, fields ...LogField) {
output(w.errorLog, levelError, v, fields...) output(w.errorLog, levelError, v, fields...)
} }
func (w *concreteWriter) Info(v interface{}, fields ...LogField) { func (w *concreteWriter) Info(v any, fields ...LogField) {
output(w.infoLog, levelInfo, v, fields...) output(w.infoLog, levelInfo, v, fields...)
} }
func (w *concreteWriter) Severe(v interface{}) { func (w *concreteWriter) Severe(v any) {
output(w.severeLog, levelFatal, v) output(w.severeLog, levelFatal, v)
} }
func (w *concreteWriter) Slow(v interface{}, fields ...LogField) { func (w *concreteWriter) Slow(v any, fields ...LogField) {
output(w.slowLog, levelSlow, v, fields...) output(w.slowLog, levelSlow, v, fields...)
} }
func (w *concreteWriter) Stack(v interface{}) { func (w *concreteWriter) Stack(v any) {
output(w.stackLog, levelError, v) output(w.stackLog, levelError, v)
} }
func (w *concreteWriter) Stat(v interface{}, fields ...LogField) { func (w *concreteWriter) Stat(v any, fields ...LogField) {
output(w.statLog, levelStat, v, fields...) output(w.statLog, levelStat, v, fields...)
} }
type nopWriter struct{} type nopWriter struct{}
func (n nopWriter) Alert(_ interface{}) { func (n nopWriter) Alert(_ any) {
} }
func (n nopWriter) Close() error { func (n nopWriter) Close() error {
return nil return nil
} }
func (n nopWriter) Debug(_ interface{}, _ ...LogField) { func (n nopWriter) Debug(_ any, _ ...LogField) {
} }
func (n nopWriter) Error(_ interface{}, _ ...LogField) { func (n nopWriter) Error(_ any, _ ...LogField) {
} }
func (n nopWriter) Info(_ interface{}, _ ...LogField) { func (n nopWriter) Info(_ any, _ ...LogField) {
} }
func (n nopWriter) Severe(_ interface{}) { func (n nopWriter) Severe(_ any) {
} }
func (n nopWriter) Slow(_ interface{}, _ ...LogField) { func (n nopWriter) Slow(_ any, _ ...LogField) {
} }
func (n nopWriter) Stack(_ interface{}) { func (n nopWriter) Stack(_ any) {
} }
func (n nopWriter) Stat(_ interface{}, _ ...LogField) { func (n nopWriter) Stat(_ any, _ ...LogField) {
} }
func buildPlainFields(fields ...LogField) []string { func buildPlainFields(fields ...LogField) []string {
@@ -277,7 +277,7 @@ func combineGlobalFields(fields []LogField) []LogField {
return ret return ret
} }
func output(writer io.Writer, level string, val interface{}, fields ...LogField) { func output(writer io.Writer, level string, val any, fields ...LogField) {
// only truncate string content, don't know how to truncate the values of other types. // only truncate string content, don't know how to truncate the values of other types.
if v, ok := val.(string); ok { if v, ok := val.(string); ok {
maxLen := atomic.LoadUint32(&maxContentLength) maxLen := atomic.LoadUint32(&maxContentLength)
@@ -330,7 +330,7 @@ func wrapLevelWithColor(level string) string {
return color.WithColorPadding(level, colour) return color.WithColorPadding(level, colour)
} }
func writeJson(writer io.Writer, info interface{}) { func writeJson(writer io.Writer, info any) {
if content, err := json.Marshal(info); err != nil { if content, err := json.Marshal(info); err != nil {
log.Println(err.Error()) log.Println(err.Error())
} else if writer == nil { } else if writer == nil {
@@ -340,7 +340,7 @@ func writeJson(writer io.Writer, info interface{}) {
} }
} }
func writePlainAny(writer io.Writer, level string, val interface{}, fields ...string) { func writePlainAny(writer io.Writer, level string, val any, fields ...string) {
level = wrapLevelWithColor(level) level = wrapLevelWithColor(level)
switch v := val.(type) { switch v := val.(type) {
@@ -377,7 +377,7 @@ func writePlainText(writer io.Writer, level, msg string, fields ...string) {
} }
} }
func writePlainValue(writer io.Writer, level string, val interface{}, fields ...string) { func writePlainValue(writer io.Writer, level string, val any, fields ...string) {
var buf bytes.Buffer var buf bytes.Buffer
buf.WriteString(getTimestamp()) buf.WriteString(getTimestamp())
buf.WriteByte(plainEncodingSep) buf.WriteByte(plainEncodingSep)

View File

@@ -108,7 +108,7 @@ func TestNopWriter(t *testing.T) {
w.Stack("foo") w.Stack("foo")
w.Stat("foo") w.Stat("foo")
w.Slow("foo") w.Slow("foo")
w.Close() _ = w.Close()
}) })
} }

View File

@@ -11,17 +11,17 @@ const jsonTagKey = "json"
var jsonUnmarshaler = NewUnmarshaler(jsonTagKey) var jsonUnmarshaler = NewUnmarshaler(jsonTagKey)
// UnmarshalJsonBytes unmarshals content into v. // UnmarshalJsonBytes unmarshals content into v.
func UnmarshalJsonBytes(content []byte, v interface{}, opts ...UnmarshalOption) error { func UnmarshalJsonBytes(content []byte, v any, opts ...UnmarshalOption) error {
return unmarshalJsonBytes(content, v, getJsonUnmarshaler(opts...)) return unmarshalJsonBytes(content, v, getJsonUnmarshaler(opts...))
} }
// UnmarshalJsonMap unmarshals content from m into v. // UnmarshalJsonMap unmarshals content from m into v.
func UnmarshalJsonMap(m map[string]interface{}, v interface{}, opts ...UnmarshalOption) error { func UnmarshalJsonMap(m map[string]any, v any, opts ...UnmarshalOption) error {
return getJsonUnmarshaler(opts...).Unmarshal(m, v) return getJsonUnmarshaler(opts...).Unmarshal(m, v)
} }
// UnmarshalJsonReader unmarshals content from reader into v. // UnmarshalJsonReader unmarshals content from reader into v.
func UnmarshalJsonReader(reader io.Reader, v interface{}, opts ...UnmarshalOption) error { func UnmarshalJsonReader(reader io.Reader, v any, opts ...UnmarshalOption) error {
return unmarshalJsonReader(reader, v, getJsonUnmarshaler(opts...)) return unmarshalJsonReader(reader, v, getJsonUnmarshaler(opts...))
} }
@@ -33,8 +33,8 @@ func getJsonUnmarshaler(opts ...UnmarshalOption) *Unmarshaler {
return jsonUnmarshaler return jsonUnmarshaler
} }
func unmarshalJsonBytes(content []byte, v interface{}, unmarshaler *Unmarshaler) error { func unmarshalJsonBytes(content []byte, v any, unmarshaler *Unmarshaler) error {
var m interface{} var m any
if err := jsonx.Unmarshal(content, &m); err != nil { if err := jsonx.Unmarshal(content, &m); err != nil {
return err return err
} }
@@ -42,8 +42,8 @@ func unmarshalJsonBytes(content []byte, v interface{}, unmarshaler *Unmarshaler)
return unmarshaler.Unmarshal(m, v) return unmarshaler.Unmarshal(m, v)
} }
func unmarshalJsonReader(reader io.Reader, v interface{}, unmarshaler *Unmarshaler) error { func unmarshalJsonReader(reader io.Reader, v any, unmarshaler *Unmarshaler) error {
var m interface{} var m any
if err := jsonx.UnmarshalFromReader(reader, &m); err != nil { if err := jsonx.UnmarshalFromReader(reader, &m); err != nil {
return err return err
} }

View File

@@ -871,7 +871,7 @@ func TestUnmarshalReaderError(t *testing.T) {
func TestUnmarshalMap(t *testing.T) { func TestUnmarshalMap(t *testing.T) {
t.Run("nil map and valid", func(t *testing.T) { t.Run("nil map and valid", func(t *testing.T) {
var m map[string]interface{} var m map[string]any
var v struct { var v struct {
Any string `json:",optional"` Any string `json:",optional"`
} }
@@ -882,7 +882,7 @@ func TestUnmarshalMap(t *testing.T) {
}) })
t.Run("empty map but not valid", func(t *testing.T) { t.Run("empty map but not valid", func(t *testing.T) {
m := map[string]interface{}{} m := map[string]any{}
var v struct { var v struct {
Any string Any string
} }
@@ -892,7 +892,7 @@ func TestUnmarshalMap(t *testing.T) {
}) })
t.Run("empty map and valid", func(t *testing.T) { t.Run("empty map and valid", func(t *testing.T) {
m := map[string]interface{}{} m := map[string]any{}
var v struct { var v struct {
Any string `json:",optional"` Any string `json:",optional"`
} }
@@ -905,7 +905,7 @@ func TestUnmarshalMap(t *testing.T) {
}) })
t.Run("valid map", func(t *testing.T) { t.Run("valid map", func(t *testing.T) {
m := map[string]interface{}{ m := map[string]any{
"Any": "foo", "Any": "foo",
} }
var v struct { var v struct {

View File

@@ -13,8 +13,8 @@ const (
// Marshal marshals the given val and returns the map that contains the fields. // Marshal marshals the given val and returns the map that contains the fields.
// optional=another is not implemented, and it's hard to implement and not common used. // optional=another is not implemented, and it's hard to implement and not common used.
func Marshal(val interface{}) (map[string]map[string]interface{}, error) { func Marshal(val any) (map[string]map[string]any, error) {
ret := make(map[string]map[string]interface{}) ret := make(map[string]map[string]any)
tp := reflect.TypeOf(val) tp := reflect.TypeOf(val)
if tp.Kind() == reflect.Ptr { if tp.Kind() == reflect.Ptr {
tp = tp.Elem() tp = tp.Elem()
@@ -45,7 +45,7 @@ func getTag(field reflect.StructField) (string, bool) {
} }
func processMember(field reflect.StructField, value reflect.Value, func processMember(field reflect.StructField, value reflect.Value,
collector map[string]map[string]interface{}) error { collector map[string]map[string]any) error {
var key string var key string
var opt *fieldOptions var opt *fieldOptions
var err error var err error
@@ -73,7 +73,7 @@ func processMember(field reflect.StructField, value reflect.Value,
if ok { if ok {
m[key] = val m[key] = val
} else { } else {
m = map[string]interface{}{ m = map[string]any{
key: val, key: val,
} }
} }

View File

@@ -227,7 +227,7 @@ func TestMarshal_Range(t *testing.T) {
} }
func TestMarshal_RangeOut(t *testing.T) { func TestMarshal_RangeOut(t *testing.T) {
tests := []interface{}{ tests := []any{
struct { struct {
Int int `json:"int,range=[1:3]"` Int int `json:"int,range=[1:3]"`
}{ }{
@@ -262,7 +262,7 @@ func TestMarshal_RangeOut(t *testing.T) {
} }
func TestMarshal_RangeIllegal(t *testing.T) { func TestMarshal_RangeIllegal(t *testing.T) {
tests := []interface{}{ tests := []any{
struct { struct {
Int int `json:"int,range=[3:1]"` Int int `json:"int,range=[3:1]"`
}{ }{
@@ -284,7 +284,7 @@ func TestMarshal_RangeIllegal(t *testing.T) {
func TestMarshal_RangeLeftEqualsToRight(t *testing.T) { func TestMarshal_RangeLeftEqualsToRight(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
value interface{} value any
err error err error
}{ }{
{ {

View File

@@ -7,7 +7,7 @@ import (
) )
// UnmarshalTomlBytes unmarshals TOML bytes into the given v. // UnmarshalTomlBytes unmarshals TOML bytes into the given v.
func UnmarshalTomlBytes(content []byte, v interface{}, opts ...UnmarshalOption) error { func UnmarshalTomlBytes(content []byte, v any, opts ...UnmarshalOption) error {
b, err := encoding.TomlToJson(content) b, err := encoding.TomlToJson(content)
if err != nil { if err != nil {
return err return err
@@ -17,7 +17,7 @@ func UnmarshalTomlBytes(content []byte, v interface{}, opts ...UnmarshalOption)
} }
// UnmarshalTomlReader unmarshals TOML from the given io.Reader into the given v. // UnmarshalTomlReader unmarshals TOML from the given io.Reader into the given v.
func UnmarshalTomlReader(r io.Reader, v interface{}, opts ...UnmarshalOption) error { func UnmarshalTomlReader(r io.Reader, v any, opts ...UnmarshalOption) error {
b, err := io.ReadAll(r) b, err := io.ReadAll(r)
if err != nil { if err != nil {
return err return err

View File

@@ -30,9 +30,9 @@ var (
durationType = reflect.TypeOf(time.Duration(0)) durationType = reflect.TypeOf(time.Duration(0))
cacheKeys = make(map[string][]string) cacheKeys = make(map[string][]string)
cacheKeysLock sync.Mutex cacheKeysLock sync.Mutex
defaultCache = make(map[string]interface{}) defaultCache = make(map[string]any)
defaultCacheLock sync.Mutex defaultCacheLock sync.Mutex
emptyMap = map[string]interface{}{} emptyMap = map[string]any{}
emptyValue = reflect.ValueOf(lang.Placeholder) emptyValue = reflect.ValueOf(lang.Placeholder)
) )
@@ -47,6 +47,7 @@ type (
UnmarshalOption func(*unmarshalOptions) UnmarshalOption func(*unmarshalOptions)
unmarshalOptions struct { unmarshalOptions struct {
fillDefault bool
fromString bool fromString bool
canonicalKey func(key string) string canonicalKey func(key string) string
} }
@@ -66,12 +67,12 @@ func NewUnmarshaler(key string, opts ...UnmarshalOption) *Unmarshaler {
} }
// UnmarshalKey unmarshals m into v with tag key. // UnmarshalKey unmarshals m into v with tag key.
func UnmarshalKey(m map[string]interface{}, v interface{}) error { func UnmarshalKey(m map[string]any, v any) error {
return keyUnmarshaler.Unmarshal(m, v) return keyUnmarshaler.Unmarshal(m, v)
} }
// Unmarshal unmarshals m into v. // Unmarshal unmarshals m into v.
func (u *Unmarshaler) Unmarshal(i interface{}, v interface{}) error { func (u *Unmarshaler) Unmarshal(i any, v any) error {
valueType := reflect.TypeOf(v) valueType := reflect.TypeOf(v)
if valueType.Kind() != reflect.Ptr { if valueType.Kind() != reflect.Ptr {
return errValueNotSettable return errValueNotSettable
@@ -79,13 +80,13 @@ func (u *Unmarshaler) Unmarshal(i interface{}, v interface{}) error {
elemType := Deref(valueType) elemType := Deref(valueType)
switch iv := i.(type) { switch iv := i.(type) {
case map[string]interface{}: case map[string]any:
if elemType.Kind() != reflect.Struct { if elemType.Kind() != reflect.Struct {
return errTypeMismatch return errTypeMismatch
} }
return u.UnmarshalValuer(mapValuer(iv), v) return u.UnmarshalValuer(mapValuer(iv), v)
case []interface{}: case []any:
if elemType.Kind() != reflect.Slice { if elemType.Kind() != reflect.Slice {
return errTypeMismatch return errTypeMismatch
} }
@@ -97,11 +98,11 @@ func (u *Unmarshaler) Unmarshal(i interface{}, v interface{}) error {
} }
// UnmarshalValuer unmarshals m into v. // UnmarshalValuer unmarshals m into v.
func (u *Unmarshaler) UnmarshalValuer(m Valuer, v interface{}) error { func (u *Unmarshaler) UnmarshalValuer(m Valuer, v any) error {
return u.unmarshalWithFullName(simpleValuer{current: m}, v, "") return u.unmarshalWithFullName(simpleValuer{current: m}, v, "")
} }
func (u *Unmarshaler) fillMap(fieldType reflect.Type, value reflect.Value, mapValue interface{}) error { func (u *Unmarshaler) fillMap(fieldType reflect.Type, value reflect.Value, mapValue any) error {
if !value.CanSet() { if !value.CanSet() {
return errValueNotSettable return errValueNotSettable
} }
@@ -121,7 +122,7 @@ func (u *Unmarshaler) fillMap(fieldType reflect.Type, value reflect.Value, mapVa
return nil return nil
} }
func (u *Unmarshaler) fillMapFromString(value reflect.Value, mapValue interface{}) error { func (u *Unmarshaler) fillMapFromString(value reflect.Value, mapValue any) error {
if !value.CanSet() { if !value.CanSet() {
return errValueNotSettable return errValueNotSettable
} }
@@ -142,7 +143,7 @@ func (u *Unmarshaler) fillMapFromString(value reflect.Value, mapValue interface{
return nil return nil
} }
func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, mapValue interface{}) error { func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, mapValue any) error {
if !value.CanSet() { if !value.CanSet() {
return errValueNotSettable return errValueNotSettable
} }
@@ -172,7 +173,7 @@ func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, map
switch dereffedBaseKind { switch dereffedBaseKind {
case reflect.Struct: case reflect.Struct:
target := reflect.New(dereffedBaseType) target := reflect.New(dereffedBaseType)
if err := u.Unmarshal(ithValue.(map[string]interface{}), target.Interface()); err != nil { if err := u.Unmarshal(ithValue.(map[string]any), target.Interface()); err != nil {
return err return err
} }
@@ -196,8 +197,8 @@ func (u *Unmarshaler) fillSlice(fieldType reflect.Type, value reflect.Value, map
} }
func (u *Unmarshaler) fillSliceFromString(fieldType reflect.Type, value reflect.Value, func (u *Unmarshaler) fillSliceFromString(fieldType reflect.Type, value reflect.Value,
mapValue interface{}) error { mapValue any) error {
var slice []interface{} var slice []any
switch v := mapValue.(type) { switch v := mapValue.(type) {
case fmt.Stringer: case fmt.Stringer:
if err := jsonx.UnmarshalFromString(v.String(), &slice); err != nil { if err := jsonx.UnmarshalFromString(v.String(), &slice); err != nil {
@@ -226,14 +227,14 @@ func (u *Unmarshaler) fillSliceFromString(fieldType reflect.Type, value reflect.
} }
func (u *Unmarshaler) fillSliceValue(slice reflect.Value, index int, func (u *Unmarshaler) fillSliceValue(slice reflect.Value, index int,
baseKind reflect.Kind, value interface{}) error { baseKind reflect.Kind, value any) error {
ithVal := slice.Index(index) ithVal := slice.Index(index)
switch v := value.(type) { switch v := value.(type) {
case fmt.Stringer: case fmt.Stringer:
return setValueFromString(baseKind, ithVal, v.String()) return setValueFromString(baseKind, ithVal, v.String())
case string: case string:
return setValueFromString(baseKind, ithVal, v) return setValueFromString(baseKind, ithVal, v)
case map[string]interface{}: case map[string]any:
return u.fillMap(ithVal.Type(), ithVal, value) return u.fillMap(ithVal.Type(), ithVal, value)
default: default:
// don't need to consider the difference between int, int8, int16, int32, int64, // don't need to consider the difference between int, int8, int16, int32, int64,
@@ -281,7 +282,7 @@ func (u *Unmarshaler) fillSliceWithDefault(derefedType reflect.Type, value refle
return u.fillSlice(derefedType, value, slice) return u.fillSlice(derefedType, value, slice)
} }
func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue interface{}) (reflect.Value, error) { func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue any) (reflect.Value, error) {
mapType := reflect.MapOf(keyType, elemType) mapType := reflect.MapOf(keyType, elemType)
valueType := reflect.TypeOf(mapValue) valueType := reflect.TypeOf(mapValue)
if mapType == valueType { if mapType == valueType {
@@ -306,7 +307,7 @@ func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue inter
targetValue.SetMapIndex(key, target.Elem()) targetValue.SetMapIndex(key, target.Elem())
case reflect.Struct: case reflect.Struct:
keythMap, ok := keythData.(map[string]interface{}) keythMap, ok := keythData.(map[string]any)
if !ok { if !ok {
return emptyValue, errTypeMismatch return emptyValue, errTypeMismatch
} }
@@ -318,7 +319,7 @@ func (u *Unmarshaler) generateMap(keyType, elemType reflect.Type, mapValue inter
SetMapIndexValue(elemType, targetValue, key, target.Elem()) SetMapIndexValue(elemType, targetValue, key, target.Elem())
case reflect.Map: case reflect.Map:
keythMap, ok := keythData.(map[string]interface{}) keythMap, ok := keythData.(map[string]any)
if !ok { if !ok {
return emptyValue, errTypeMismatch return emptyValue, errTypeMismatch
} }
@@ -513,7 +514,7 @@ func (u *Unmarshaler) processFieldNotFromString(fieldType reflect.Type, value re
switch { switch {
case valueKind == reflect.Map && typeKind == reflect.Struct: case valueKind == reflect.Map && typeKind == reflect.Struct:
mv, ok := mapValue.(map[string]interface{}) mv, ok := mapValue.(map[string]any)
if !ok { if !ok {
return errTypeMismatch return errTypeMismatch
} }
@@ -536,7 +537,7 @@ func (u *Unmarshaler) processFieldNotFromString(fieldType reflect.Type, value re
} }
func (u *Unmarshaler) processFieldPrimitive(fieldType reflect.Type, value reflect.Value, func (u *Unmarshaler) processFieldPrimitive(fieldType reflect.Type, value reflect.Value,
mapValue interface{}, opts *fieldOptionsWithContext, fullName string) error { mapValue any, opts *fieldOptionsWithContext, fullName string) error {
typeKind := Deref(fieldType).Kind() typeKind := Deref(fieldType).Kind()
valueKind := reflect.TypeOf(mapValue).Kind() valueKind := reflect.TypeOf(mapValue).Kind()
@@ -631,7 +632,7 @@ func (u *Unmarshaler) processFieldStruct(fieldType reflect.Type, value reflect.V
} }
func (u *Unmarshaler) processFieldTextUnmarshaler(fieldType reflect.Type, value reflect.Value, func (u *Unmarshaler) processFieldTextUnmarshaler(fieldType reflect.Type, value reflect.Value,
mapValue interface{}) (bool, error) { mapValue any) (bool, error) {
var tval encoding.TextUnmarshaler var tval encoding.TextUnmarshaler
var ok bool var ok bool
@@ -710,7 +711,14 @@ func (u *Unmarshaler) processNamedField(field reflect.StructField, value reflect
valuer := createValuer(m, opts) valuer := createValuer(m, opts)
mapValue, hasValue := getValue(valuer, canonicalKey) mapValue, hasValue := getValue(valuer, canonicalKey)
if !hasValue {
// When fillDefault is used, m is a null value, hasValue must be false, all priority judgments fillDefault.
if u.opts.fillDefault {
if !value.IsZero() {
return fmt.Errorf("set the default value, %s must be zero", fullName)
}
return u.processNamedFieldWithoutValue(field.Type, value, opts, fullName)
} else if !hasValue {
return u.processNamedFieldWithoutValue(field.Type, value, opts, fullName) return u.processNamedFieldWithoutValue(field.Type, value, opts, fullName)
} }
@@ -756,7 +764,7 @@ func (u *Unmarshaler) processNamedFieldWithValue(fieldType reflect.Type, value r
} }
func (u *Unmarshaler) processNamedFieldWithValueFromString(fieldType reflect.Type, value reflect.Value, func (u *Unmarshaler) processNamedFieldWithValueFromString(fieldType reflect.Type, value reflect.Value,
mapValue interface{}, key string, opts *fieldOptionsWithContext, fullName string) error { mapValue any, key string, opts *fieldOptionsWithContext, fullName string) error {
valueKind := reflect.TypeOf(mapValue).Kind() valueKind := reflect.TypeOf(mapValue).Kind()
if valueKind != reflect.String { if valueKind != reflect.String {
return fmt.Errorf("the value in map is not string, but %s", valueKind) return fmt.Errorf("the value in map is not string, but %s", valueKind)
@@ -801,6 +809,10 @@ func (u *Unmarshaler) processNamedFieldWithoutValue(fieldType reflect.Type, valu
} }
} }
if u.opts.fillDefault {
return nil
}
switch fieldKind { switch fieldKind {
case reflect.Array, reflect.Map, reflect.Slice: case reflect.Array, reflect.Map, reflect.Slice:
if !opts.optional() { if !opts.optional() {
@@ -832,7 +844,7 @@ func (u *Unmarshaler) processNamedFieldWithoutValue(fieldType reflect.Type, valu
return nil return nil
} }
func (u *Unmarshaler) unmarshalWithFullName(m valuerWithParent, v interface{}, fullName string) error { func (u *Unmarshaler) unmarshalWithFullName(m valuerWithParent, v any, fullName string) error {
rv := reflect.ValueOf(v) rv := reflect.ValueOf(v)
if err := ValidatePtr(&rv); err != nil { if err := ValidatePtr(&rv); err != nil {
return err return err
@@ -853,7 +865,12 @@ func (u *Unmarshaler) unmarshalWithFullName(m valuerWithParent, v interface{}, f
numFields := baseType.NumField() numFields := baseType.NumField()
for i := 0; i < numFields; i++ { for i := 0; i < numFields; i++ {
if err := u.processField(baseType.Field(i), valElem.Field(i), m, fullName); err != nil { field := baseType.Field(i)
if !field.IsExported() {
continue
}
if err := u.processField(field, valElem.Field(i), m, fullName); err != nil {
return err return err
} }
} }
@@ -868,13 +885,20 @@ func WithStringValues() UnmarshalOption {
} }
} }
// WithCanonicalKeyFunc customizes an Unmarshaler with Canonical Key func // WithCanonicalKeyFunc customizes an Unmarshaler with Canonical Key func.
func WithCanonicalKeyFunc(f func(string) string) UnmarshalOption { func WithCanonicalKeyFunc(f func(string) string) UnmarshalOption {
return func(opt *unmarshalOptions) { return func(opt *unmarshalOptions) {
opt.canonicalKey = f opt.canonicalKey = f
} }
} }
// WithDefault customizes an Unmarshaler with fill default values.
func WithDefault() UnmarshalOption {
return func(opt *unmarshalOptions) {
opt.fillDefault = true
}
}
func createValuer(v valuerWithParent, opts *fieldOptionsWithContext) valuerWithParent { func createValuer(v valuerWithParent, opts *fieldOptionsWithContext) valuerWithParent {
if opts.inherit() { if opts.inherit() {
return recursiveValuer{ return recursiveValuer{
@@ -900,7 +924,7 @@ func fillDurationValue(fieldType reflect.Type, value reflect.Value, dur string)
return nil return nil
} }
func fillPrimitive(fieldType reflect.Type, value reflect.Value, mapValue interface{}, func fillPrimitive(fieldType reflect.Type, value reflect.Value, mapValue any,
opts *fieldOptionsWithContext, fullName string) error { opts *fieldOptionsWithContext, fullName string) error {
if !value.CanSet() { if !value.CanSet() {
return errValueNotSettable return errValueNotSettable
@@ -929,7 +953,7 @@ func fillPrimitive(fieldType reflect.Type, value reflect.Value, mapValue interfa
} }
} }
func fillWithSameType(fieldType reflect.Type, value reflect.Value, mapValue interface{}, func fillWithSameType(fieldType reflect.Type, value reflect.Value, mapValue any,
opts *fieldOptionsWithContext) error { opts *fieldOptionsWithContext) error {
if !value.CanSet() { if !value.CanSet() {
return errValueNotSettable return errValueNotSettable
@@ -952,12 +976,12 @@ func fillWithSameType(fieldType reflect.Type, value reflect.Value, mapValue inte
} }
// getValue gets the value for the specific key, the key can be in the format of parentKey.childKey // getValue gets the value for the specific key, the key can be in the format of parentKey.childKey
func getValue(m valuerWithParent, key string) (interface{}, bool) { func getValue(m valuerWithParent, key string) (any, bool) {
keys := readKeys(key) keys := readKeys(key)
return getValueWithChainedKeys(m, keys) return getValueWithChainedKeys(m, keys)
} }
func getValueWithChainedKeys(m valuerWithParent, keys []string) (interface{}, bool) { func getValueWithChainedKeys(m valuerWithParent, keys []string) (any, bool) {
switch len(keys) { switch len(keys) {
case 0: case 0:
return nil, false return nil, false
@@ -966,7 +990,7 @@ func getValueWithChainedKeys(m valuerWithParent, keys []string) (interface{}, bo
return v, ok return v, ok
default: default:
if v, ok := m.Value(keys[0]); ok { if v, ok := m.Value(keys[0]); ok {
if nextm, ok := v.(map[string]interface{}); ok { if nextm, ok := v.(map[string]any); ok {
return getValueWithChainedKeys(recursiveValuer{ return getValueWithChainedKeys(recursiveValuer{
current: mapValuer(nextm), current: mapValuer(nextm),
parent: m, parent: m,
@@ -1004,7 +1028,7 @@ func newInitError(name string) error {
} }
func newTypeMismatchError(name string) error { func newTypeMismatchError(name string) error {
return fmt.Errorf("error: type mismatch for field %s", name) return fmt.Errorf("type mismatch for field %s", name)
} }
func readKeys(key string) []string { func readKeys(key string) []string {
@@ -1025,7 +1049,7 @@ func readKeys(key string) []string {
return keys return keys
} }
func setSameKindValue(targetType reflect.Type, target reflect.Value, value interface{}) { func setSameKindValue(targetType reflect.Type, target reflect.Value, value any) {
if reflect.ValueOf(value).Type().AssignableTo(targetType) { if reflect.ValueOf(value).Type().AssignableTo(targetType) {
target.Set(reflect.ValueOf(value)) target.Set(reflect.ValueOf(value))
} else { } else {

File diff suppressed because it is too large Load Diff

View File

@@ -64,7 +64,7 @@ func Deref(t reflect.Type) reflect.Type {
} }
// Repr returns the string representation of v. // Repr returns the string representation of v.
func Repr(v interface{}) string { func Repr(v any) string {
return lang.Repr(v) return lang.Repr(v)
} }
@@ -89,7 +89,7 @@ func ValidatePtr(v *reflect.Value) error {
return nil return nil
} }
func convertTypeFromString(kind reflect.Kind, str string) (interface{}, error) { func convertTypeFromString(kind reflect.Kind, str string) (any, error) {
switch kind { switch kind {
case reflect.Bool: case reflect.Bool:
switch strings.ToLower(str) { switch strings.ToLower(str) {
@@ -484,7 +484,7 @@ func parseSegments(val string) []string {
return segments return segments
} }
func setMatchedPrimitiveValue(kind reflect.Kind, value reflect.Value, v interface{}) error { func setMatchedPrimitiveValue(kind reflect.Kind, value reflect.Value, v any) error {
switch kind { switch kind {
case reflect.Bool: case reflect.Bool:
value.SetBool(v.(bool)) value.SetBool(v.(bool))
@@ -536,7 +536,7 @@ func structValueRequired(tag string, tp reflect.Type) (bool, error) {
return required, err return required, err
} }
func toFloat64(v interface{}) (float64, bool) { func toFloat64(v any) (float64, bool) {
switch val := v.(type) { switch val := v.(type) {
case int: case int:
return float64(val), true return float64(val), true
@@ -623,7 +623,7 @@ func validateNumberRange(fv float64, nr *numberRange) error {
return nil return nil
} }
func validateValueInOptions(val interface{}, options []string) error { func validateValueInOptions(val any, options []string) error {
if len(options) > 0 { if len(options) > 0 {
switch v := val.(type) { switch v := val.(type) {
case string: case string:
@@ -640,7 +640,7 @@ func validateValueInOptions(val interface{}, options []string) error {
return nil return nil
} }
func validateValueRange(mapValue interface{}, opts *fieldOptionsWithContext) error { func validateValueRange(mapValue any, opts *fieldOptionsWithContext) error {
if opts == nil || opts.Range == nil { if opts == nil || opts.Range == nil {
return nil return nil
} }

View File

@@ -258,7 +258,7 @@ func TestSetValueFormatErrors(t *testing.T) {
IntValue int IntValue int
UintValue uint UintValue uint
FloatValue float32 FloatValue float32
MapValue map[string]interface{} MapValue map[string]any
} }
var bar Bar var bar Bar

View File

@@ -4,7 +4,7 @@ type (
// A Valuer interface defines the way to get values from the underlying object with keys. // A Valuer interface defines the way to get values from the underlying object with keys.
Valuer interface { Valuer interface {
// Value gets the value associated with the given key. // Value gets the value associated with the given key.
Value(key string) (interface{}, bool) Value(key string) (any, bool)
} }
// A valuerWithParent defines a node that has a parent node. // A valuerWithParent defines a node that has a parent node.
@@ -22,12 +22,12 @@ type (
// A valueWithParent is used to wrap the value with its parent. // A valueWithParent is used to wrap the value with its parent.
valueWithParent struct { valueWithParent struct {
value interface{} value any
parent valuerWithParent parent valuerWithParent
} }
// mapValuer is a type for map to meet the Valuer interface. // mapValuer is a type for map to meet the Valuer interface.
mapValuer map[string]interface{} mapValuer map[string]any
// simpleValuer is a type to get value from current node. // simpleValuer is a type to get value from current node.
simpleValuer node simpleValuer node
// recursiveValuer is a type to get the value recursively from current and parent nodes. // recursiveValuer is a type to get the value recursively from current and parent nodes.
@@ -35,13 +35,13 @@ type (
) )
// Value gets the value assciated with the given key from mv. // Value gets the value assciated with the given key from mv.
func (mv mapValuer) Value(key string) (interface{}, bool) { func (mv mapValuer) Value(key string) (any, bool) {
v, ok := mv[key] v, ok := mv[key]
return v, ok return v, ok
} }
// Value gets the value associated with the given key from sv. // Value gets the value associated with the given key from sv.
func (sv simpleValuer) Value(key string) (interface{}, bool) { func (sv simpleValuer) Value(key string) (any, bool) {
v, ok := sv.current.Value(key) v, ok := sv.current.Value(key)
return v, ok return v, ok
} }
@@ -60,7 +60,7 @@ func (sv simpleValuer) Parent() valuerWithParent {
// Value gets the value associated with the given key from rv, // Value gets the value associated with the given key from rv,
// and it will inherit the value from parent nodes. // and it will inherit the value from parent nodes.
func (rv recursiveValuer) Value(key string) (interface{}, bool) { func (rv recursiveValuer) Value(key string) (any, bool) {
val, ok := rv.current.Value(key) val, ok := rv.current.Value(key)
if !ok { if !ok {
if parent := rv.Parent(); parent != nil { if parent := rv.Parent(); parent != nil {
@@ -70,7 +70,7 @@ func (rv recursiveValuer) Value(key string) (interface{}, bool) {
return nil, false return nil, false
} }
vm, ok := val.(map[string]interface{}) vm, ok := val.(map[string]any)
if !ok { if !ok {
return val, true return val, true
} }
@@ -85,7 +85,7 @@ func (rv recursiveValuer) Value(key string) (interface{}, bool) {
return val, true return val, true
} }
pm, ok := pv.(map[string]interface{}) pm, ok := pv.(map[string]any)
if !ok { if !ok {
return val, true return val, true
} }

View File

@@ -7,17 +7,17 @@ import (
) )
func TestMapValuerWithInherit_Value(t *testing.T) { func TestMapValuerWithInherit_Value(t *testing.T) {
input := map[string]interface{}{ input := map[string]any{
"discovery": map[string]interface{}{ "discovery": map[string]any{
"host": "localhost", "host": "localhost",
"port": 8080, "port": 8080,
}, },
"component": map[string]interface{}{ "component": map[string]any{
"name": "test", "name": "test",
}, },
} }
valuer := recursiveValuer{ valuer := recursiveValuer{
current: mapValuer(input["component"].(map[string]interface{})), current: mapValuer(input["component"].(map[string]any)),
parent: simpleValuer{ parent: simpleValuer{
current: mapValuer(input), current: mapValuer(input),
}, },
@@ -26,24 +26,24 @@ func TestMapValuerWithInherit_Value(t *testing.T) {
val, ok := valuer.Value("discovery") val, ok := valuer.Value("discovery")
assert.True(t, ok) assert.True(t, ok)
m, ok := val.(map[string]interface{}) m, ok := val.(map[string]any)
assert.True(t, ok) assert.True(t, ok)
assert.Equal(t, "localhost", m["host"]) assert.Equal(t, "localhost", m["host"])
assert.Equal(t, 8080, m["port"]) assert.Equal(t, 8080, m["port"])
} }
func TestRecursiveValuer_Value(t *testing.T) { func TestRecursiveValuer_Value(t *testing.T) {
input := map[string]interface{}{ input := map[string]any{
"component": map[string]interface{}{ "component": map[string]any{
"name": "test", "name": "test",
"foo": map[string]interface{}{ "foo": map[string]any{
"bar": "baz", "bar": "baz",
}, },
}, },
"foo": "value", "foo": "value",
} }
valuer := recursiveValuer{ valuer := recursiveValuer{
current: mapValuer(input["component"].(map[string]interface{})), current: mapValuer(input["component"].(map[string]any)),
parent: simpleValuer{ parent: simpleValuer{
current: mapValuer(input), current: mapValuer(input),
}, },
@@ -51,7 +51,7 @@ func TestRecursiveValuer_Value(t *testing.T) {
val, ok := valuer.Value("foo") val, ok := valuer.Value("foo")
assert.True(t, ok) assert.True(t, ok)
assert.EqualValues(t, map[string]interface{}{ assert.EqualValues(t, map[string]any{
"bar": "baz", "bar": "baz",
}, val) }, val)
} }

View File

@@ -7,7 +7,7 @@ import (
) )
// UnmarshalYamlBytes unmarshals content into v. // UnmarshalYamlBytes unmarshals content into v.
func UnmarshalYamlBytes(content []byte, v interface{}, opts ...UnmarshalOption) error { func UnmarshalYamlBytes(content []byte, v any, opts ...UnmarshalOption) error {
b, err := encoding.YamlToJson(content) b, err := encoding.YamlToJson(content)
if err != nil { if err != nil {
return err return err
@@ -17,7 +17,7 @@ func UnmarshalYamlBytes(content []byte, v interface{}, opts ...UnmarshalOption)
} }
// UnmarshalYamlReader unmarshals content from reader into v. // UnmarshalYamlReader unmarshals content from reader into v.
func UnmarshalYamlReader(reader io.Reader, v interface{}, opts ...UnmarshalOption) error { func UnmarshalYamlReader(reader io.Reader, v any, opts ...UnmarshalOption) error {
b, err := io.ReadAll(reader) b, err := io.ReadAll(reader)
if err != nil { if err != nil {
return err return err

View File

@@ -5,7 +5,7 @@ import "math"
const epsilon = 1e-6 const epsilon = 1e-6
// CalcEntropy calculates the entropy of m. // CalcEntropy calculates the entropy of m.
func CalcEntropy(m map[interface{}]int) float64 { func CalcEntropy(m map[any]int) float64 {
if len(m) == 0 || len(m) == 1 { if len(m) == 0 || len(m) == 1 {
return 1 return 1
} }

View File

@@ -9,7 +9,7 @@ import (
func TestCalcEntropy(t *testing.T) { func TestCalcEntropy(t *testing.T) {
const total = 1000 const total = 1000
const count = 100 const count = 100
m := make(map[interface{}]int, total) m := make(map[any]int, total)
for i := 0; i < total; i++ { for i := 0; i < total; i++ {
m[i] = count m[i] = count
} }

View File

@@ -61,7 +61,7 @@ func TestUnstable_Distribution(t *testing.T) {
_, ok := m[0] _, ok := m[0]
assert.False(t, ok) assert.False(t, ok)
mi := make(map[interface{}]int, len(m)) mi := make(map[any]int, len(m))
for k, v := range m { for k, v := range m {
mi[k] = v mi[k] = v
} }

View File

@@ -5,6 +5,7 @@ import (
"github.com/prometheus/client_golang/prometheus/testutil" "github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/proc"
"github.com/zeromicro/go-zero/core/prometheus" "github.com/zeromicro/go-zero/core/prometheus"
) )
@@ -17,6 +18,9 @@ func TestNewCounterVec(t *testing.T) {
}) })
defer counterVec.close() defer counterVec.close()
counterVecNil := NewCounterVec(nil) counterVecNil := NewCounterVec(nil)
counterVec.Inc("path", "code")
counterVec.Add(1, "path", "code")
proc.Shutdown()
assert.NotNil(t, counterVec) assert.NotNil(t, counterVec)
assert.Nil(t, counterVecNil) assert.Nil(t, counterVecNil)
} }

View File

@@ -5,6 +5,7 @@ import (
"github.com/prometheus/client_golang/prometheus/testutil" "github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/proc"
) )
func TestNewGaugeVec(t *testing.T) { func TestNewGaugeVec(t *testing.T) {
@@ -18,6 +19,8 @@ func TestNewGaugeVec(t *testing.T) {
gaugeVecNil := NewGaugeVec(nil) gaugeVecNil := NewGaugeVec(nil)
assert.NotNil(t, gaugeVec) assert.NotNil(t, gaugeVec)
assert.Nil(t, gaugeVecNil) assert.Nil(t, gaugeVecNil)
proc.Shutdown()
} }
func TestGaugeInc(t *testing.T) { func TestGaugeInc(t *testing.T) {

View File

@@ -6,6 +6,7 @@ import (
"github.com/prometheus/client_golang/prometheus/testutil" "github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/proc"
) )
func TestNewHistogramVec(t *testing.T) { func TestNewHistogramVec(t *testing.T) {
@@ -47,4 +48,6 @@ func TestHistogramObserve(t *testing.T) {
err := testutil.CollectAndCompare(hv.histogram, strings.NewReader(metadata+val)) err := testutil.CollectAndCompare(hv.histogram, strings.NewReader(metadata+val))
assert.Nil(t, err) assert.Nil(t, err)
proc.Shutdown()
} }

View File

@@ -7,7 +7,6 @@ import (
"sync/atomic" "sync/atomic"
"github.com/zeromicro/go-zero/core/errorx" "github.com/zeromicro/go-zero/core/errorx"
"github.com/zeromicro/go-zero/core/lang"
) )
const ( const (
@@ -24,30 +23,30 @@ var (
type ( type (
// ForEachFunc is used to do element processing, but no output. // ForEachFunc is used to do element processing, but no output.
ForEachFunc func(item interface{}) ForEachFunc[T any] func(item T)
// GenerateFunc is used to let callers send elements into source. // GenerateFunc is used to let callers send elements into source.
GenerateFunc func(source chan<- interface{}) GenerateFunc[T any] func(source chan<- T)
// MapFunc is used to do element processing and write the output to writer. // MapFunc is used to do element processing and write the output to writer.
MapFunc func(item interface{}, writer Writer) MapFunc[T, U any] func(item T, writer Writer[U])
// MapperFunc is used to do element processing and write the output to writer, // MapperFunc is used to do element processing and write the output to writer,
// use cancel func to cancel the processing. // use cancel func to cancel the processing.
MapperFunc func(item interface{}, writer Writer, cancel func(error)) MapperFunc[T, U any] func(item T, writer Writer[U], cancel func(error))
// ReducerFunc is used to reduce all the mapping output and write to writer, // ReducerFunc is used to reduce all the mapping output and write to writer,
// use cancel func to cancel the processing. // use cancel func to cancel the processing.
ReducerFunc func(pipe <-chan interface{}, writer Writer, cancel func(error)) ReducerFunc[U, V any] func(pipe <-chan U, writer Writer[V], cancel func(error))
// VoidReducerFunc is used to reduce all the mapping output, but no output. // VoidReducerFunc is used to reduce all the mapping output, but no output.
// Use cancel func to cancel the processing. // Use cancel func to cancel the processing.
VoidReducerFunc func(pipe <-chan interface{}, cancel func(error)) VoidReducerFunc[U any] func(pipe <-chan U, cancel func(error))
// Option defines the method to customize the mapreduce. // Option defines the method to customize the mapreduce.
Option func(opts *mapReduceOptions) Option func(opts *mapReduceOptions)
mapperContext struct { mapperContext[T, U any] struct {
ctx context.Context ctx context.Context
mapper MapFunc mapper MapFunc[T, U]
source <-chan interface{} source <-chan T
panicChan *onceChan panicChan *onceChan
collector chan<- interface{} collector chan<- U
doneChan <-chan lang.PlaceholderType doneChan <-chan struct{}
workers int workers int
} }
@@ -57,8 +56,8 @@ type (
} }
// Writer interface wraps Write method. // Writer interface wraps Write method.
Writer interface { Writer[T any] interface {
Write(v interface{}) Write(v T)
} }
) )
@@ -68,16 +67,15 @@ func Finish(fns ...func() error) error {
return nil return nil
} }
return MapReduceVoid(func(source chan<- interface{}) { return MapReduceVoid(func(source chan<- func() error) {
for _, fn := range fns { for _, fn := range fns {
source <- fn source <- fn
} }
}, func(item interface{}, writer Writer, cancel func(error)) { }, func(fn func() error, writer Writer[any], cancel func(error)) {
fn := item.(func() error)
if err := fn(); err != nil { if err := fn(); err != nil {
cancel(err) cancel(err)
} }
}, func(pipe <-chan interface{}, cancel func(error)) { }, func(pipe <-chan any, cancel func(error)) {
}, WithWorkers(len(fns))) }, WithWorkers(len(fns)))
} }
@@ -87,27 +85,26 @@ func FinishVoid(fns ...func()) {
return return
} }
ForEach(func(source chan<- interface{}) { ForEach(func(source chan<- func()) {
for _, fn := range fns { for _, fn := range fns {
source <- fn source <- fn
} }
}, func(item interface{}) { }, func(fn func()) {
fn := item.(func())
fn() fn()
}, WithWorkers(len(fns))) }, WithWorkers(len(fns)))
} }
// ForEach maps all elements from given generate but no output. // ForEach maps all elements from given generate but no output.
func ForEach(generate GenerateFunc, mapper ForEachFunc, opts ...Option) { func ForEach[T any](generate GenerateFunc[T], mapper ForEachFunc[T], opts ...Option) {
options := buildOptions(opts...) options := buildOptions(opts...)
panicChan := &onceChan{channel: make(chan interface{})} panicChan := &onceChan{channel: make(chan any)}
source := buildSource(generate, panicChan) source := buildSource(generate, panicChan)
collector := make(chan interface{}) collector := make(chan any)
done := make(chan lang.PlaceholderType) done := make(chan struct{})
go executeMappers(mapperContext{ go executeMappers(mapperContext[T, any]{
ctx: options.ctx, ctx: options.ctx,
mapper: func(item interface{}, _ Writer) { mapper: func(item T, _ Writer[any]) {
mapper(item) mapper(item)
}, },
source: source, source: source,
@@ -131,26 +128,26 @@ func ForEach(generate GenerateFunc, mapper ForEachFunc, opts ...Option) {
// MapReduce maps all elements generated from given generate func, // MapReduce maps all elements generated from given generate func,
// and reduces the output elements with given reducer. // and reduces the output elements with given reducer.
func MapReduce(generate GenerateFunc, mapper MapperFunc, reducer ReducerFunc, func MapReduce[T, U, V any](generate GenerateFunc[T], mapper MapperFunc[T, U], reducer ReducerFunc[U, V],
opts ...Option) (interface{}, error) { opts ...Option) (V, error) {
panicChan := &onceChan{channel: make(chan interface{})} panicChan := &onceChan{channel: make(chan any)}
source := buildSource(generate, panicChan) source := buildSource(generate, panicChan)
return mapReduceWithPanicChan(source, panicChan, mapper, reducer, opts...) return mapReduceWithPanicChan(source, panicChan, mapper, reducer, opts...)
} }
// MapReduceChan maps all elements from source, and reduce the output elements with given reducer. // MapReduceChan maps all elements from source, and reduce the output elements with given reducer.
func MapReduceChan(source <-chan interface{}, mapper MapperFunc, reducer ReducerFunc, func MapReduceChan[T, U, V any](source <-chan T, mapper MapperFunc[T, U], reducer ReducerFunc[U, V],
opts ...Option) (interface{}, error) { opts ...Option) (V, error) {
panicChan := &onceChan{channel: make(chan interface{})} panicChan := &onceChan{channel: make(chan any)}
return mapReduceWithPanicChan(source, panicChan, mapper, reducer, opts...) return mapReduceWithPanicChan(source, panicChan, mapper, reducer, opts...)
} }
// mapReduceWithPanicChan maps all elements from source, and reduce the output elements with given reducer. // mapReduceWithPanicChan maps all elements from source, and reduce the output elements with given reducer.
func mapReduceWithPanicChan(source <-chan interface{}, panicChan *onceChan, mapper MapperFunc, func mapReduceWithPanicChan[T, U, V any](source <-chan T, panicChan *onceChan, mapper MapperFunc[T, U],
reducer ReducerFunc, opts ...Option) (interface{}, error) { reducer ReducerFunc[U, V], opts ...Option) (val V, err error) {
options := buildOptions(opts...) options := buildOptions(opts...)
// output is used to write the final result // output is used to write the final result
output := make(chan interface{}) output := make(chan V)
defer func() { defer func() {
// reducer can only write once, if more, panic // reducer can only write once, if more, panic
for range output { for range output {
@@ -159,12 +156,12 @@ func mapReduceWithPanicChan(source <-chan interface{}, panicChan *onceChan, mapp
}() }()
// collector is used to collect data from mapper, and consume in reducer // collector is used to collect data from mapper, and consume in reducer
collector := make(chan interface{}, options.workers) collector := make(chan U, options.workers)
// if done is closed, all mappers and reducer should stop processing // if done is closed, all mappers and reducer should stop processing
done := make(chan lang.PlaceholderType) done := make(chan struct{})
writer := newGuardedWriter(options.ctx, output, done) writer := newGuardedWriter(options.ctx, output, done)
var closeOnce sync.Once var closeOnce sync.Once
// use atomic.Value to avoid data race // use atomic type to avoid data race
var retErr errorx.AtomicError var retErr errorx.AtomicError
finish := func() { finish := func() {
closeOnce.Do(func() { closeOnce.Do(func() {
@@ -195,9 +192,9 @@ func mapReduceWithPanicChan(source <-chan interface{}, panicChan *onceChan, mapp
reducer(collector, writer, cancel) reducer(collector, writer, cancel)
}() }()
go executeMappers(mapperContext{ go executeMappers(mapperContext[T, U]{
ctx: options.ctx, ctx: options.ctx,
mapper: func(item interface{}, w Writer) { mapper: func(item T, w Writer[U]) {
mapper(item, w, cancel) mapper(item, w, cancel)
}, },
source: source, source: source,
@@ -210,26 +207,29 @@ func mapReduceWithPanicChan(source <-chan interface{}, panicChan *onceChan, mapp
select { select {
case <-options.ctx.Done(): case <-options.ctx.Done():
cancel(context.DeadlineExceeded) cancel(context.DeadlineExceeded)
return nil, context.DeadlineExceeded err = context.DeadlineExceeded
case v := <-panicChan.channel: case v := <-panicChan.channel:
// drain output here, otherwise for loop panic in defer // drain output here, otherwise for loop panic in defer
drain(output) drain(output)
panic(v) panic(v)
case v, ok := <-output: case v, ok := <-output:
if err := retErr.Load(); err != nil { if e := retErr.Load(); e != nil {
return nil, err err = e
} else if ok { } else if ok {
return v, nil val = v
} else { } else {
return nil, ErrReduceNoOutput err = ErrReduceNoOutput
} }
} }
return
} }
// MapReduceVoid maps all elements generated from given generate, // MapReduceVoid maps all elements generated from given generate,
// and reduce the output elements with given reducer. // and reduce the output elements with given reducer.
func MapReduceVoid(generate GenerateFunc, mapper MapperFunc, reducer VoidReducerFunc, opts ...Option) error { func MapReduceVoid[T, U any](generate GenerateFunc[T], mapper MapperFunc[T, U],
_, err := MapReduce(generate, mapper, func(input <-chan interface{}, writer Writer, cancel func(error)) { reducer VoidReducerFunc[U], opts ...Option) error {
_, err := MapReduce(generate, mapper, func(input <-chan U, writer Writer[any], cancel func(error)) {
reducer(input, cancel) reducer(input, cancel)
}, opts...) }, opts...)
if errors.Is(err, ErrReduceNoOutput) { if errors.Is(err, ErrReduceNoOutput) {
@@ -266,8 +266,8 @@ func buildOptions(opts ...Option) *mapReduceOptions {
return options return options
} }
func buildSource(generate GenerateFunc, panicChan *onceChan) chan interface{} { func buildSource[T any](generate GenerateFunc[T], panicChan *onceChan) chan T {
source := make(chan interface{}) source := make(chan T)
go func() { go func() {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
@@ -283,13 +283,13 @@ func buildSource(generate GenerateFunc, panicChan *onceChan) chan interface{} {
} }
// drain drains the channel. // drain drains the channel.
func drain(channel <-chan interface{}) { func drain[T any](channel <-chan T) {
// drain the channel // drain the channel
for range channel { for range channel {
} }
} }
func executeMappers(mCtx mapperContext) { func executeMappers[T, U any](mCtx mapperContext[T, U]) {
var wg sync.WaitGroup var wg sync.WaitGroup
defer func() { defer func() {
wg.Wait() wg.Wait()
@@ -298,7 +298,7 @@ func executeMappers(mCtx mapperContext) {
}() }()
var failed int32 var failed int32
pool := make(chan lang.PlaceholderType, mCtx.workers) pool := make(chan struct{}, mCtx.workers)
writer := newGuardedWriter(mCtx.ctx, mCtx.collector, mCtx.doneChan) writer := newGuardedWriter(mCtx.ctx, mCtx.collector, mCtx.doneChan)
for atomic.LoadInt32(&failed) == 0 { for atomic.LoadInt32(&failed) == 0 {
select { select {
@@ -306,7 +306,7 @@ func executeMappers(mCtx mapperContext) {
return return
case <-mCtx.doneChan: case <-mCtx.doneChan:
return return
case pool <- lang.Placeholder: case pool <- struct{}{}:
item, ok := <-mCtx.source item, ok := <-mCtx.source
if !ok { if !ok {
<-pool <-pool
@@ -346,22 +346,21 @@ func once(fn func(error)) func(error) {
} }
} }
type guardedWriter struct { type guardedWriter[T any] struct {
ctx context.Context ctx context.Context
channel chan<- interface{} channel chan<- T
done <-chan lang.PlaceholderType done <-chan struct{}
} }
func newGuardedWriter(ctx context.Context, channel chan<- interface{}, func newGuardedWriter[T any](ctx context.Context, channel chan<- T, done <-chan struct{}) guardedWriter[T] {
done <-chan lang.PlaceholderType) guardedWriter { return guardedWriter[T]{
return guardedWriter{
ctx: ctx, ctx: ctx,
channel: channel, channel: channel,
done: done, done: done,
} }
} }
func (gw guardedWriter) Write(v interface{}) { func (gw guardedWriter[T]) Write(v T) {
select { select {
case <-gw.ctx.Done(): case <-gw.ctx.Done():
return return
@@ -373,11 +372,11 @@ func (gw guardedWriter) Write(v interface{}) {
} }
type onceChan struct { type onceChan struct {
channel chan interface{} channel chan any
wrote int32 wrote int32
} }
func (oc *onceChan) write(val interface{}) { func (oc *onceChan) write(val any) {
if atomic.CompareAndSwapInt32(&oc.wrote, 0, 1) { if atomic.CompareAndSwapInt32(&oc.wrote, 0, 1) {
oc.channel <- val oc.channel <- val
} }

View File

@@ -1,6 +1,3 @@
//go:build go1.18
// +build go1.18
package mr package mr
import ( import (
@@ -18,9 +15,9 @@ import (
func FuzzMapReduce(f *testing.F) { func FuzzMapReduce(f *testing.F) {
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
f.Add(uint(10), uint(runtime.NumCPU())) f.Add(int64(10), runtime.NumCPU())
f.Fuzz(func(t *testing.T, num, workers uint) { f.Fuzz(func(t *testing.T, n int64, workers int) {
n := int64(num)%5000 + 5000 n = n%5000 + 5000
genPanic := rand.Intn(100) == 0 genPanic := rand.Intn(100) == 0
mapperPanic := rand.Intn(100) == 0 mapperPanic := rand.Intn(100) == 0
reducerPanic := rand.Intn(100) == 0 reducerPanic := rand.Intn(100) == 0
@@ -29,34 +26,33 @@ func FuzzMapReduce(f *testing.F) {
reducerIdx := rand.Int63n(n) reducerIdx := rand.Int63n(n)
squareSum := (n - 1) * n * (2*n - 1) / 6 squareSum := (n - 1) * n * (2*n - 1) / 6
fn := func() (interface{}, error) { fn := func() (int64, error) {
defer goleak.VerifyNone(t, goleak.IgnoreCurrent()) defer goleak.VerifyNone(t, goleak.IgnoreCurrent())
return MapReduce(func(source chan<- interface{}) { return MapReduce(func(source chan<- int64) {
for i := int64(0); i < n; i++ { for i := int64(0); i < n; i++ {
source <- i source <- i
if genPanic && i == genIdx { if genPanic && i == genIdx {
panic("foo") panic("foo")
} }
} }
}, func(item interface{}, writer Writer, cancel func(error)) { }, func(v int64, writer Writer[int64], cancel func(error)) {
v := item.(int64)
if mapperPanic && v == mapperIdx { if mapperPanic && v == mapperIdx {
panic("bar") panic("bar")
} }
writer.Write(v * v) writer.Write(v * v)
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) { }, func(pipe <-chan int64, writer Writer[int64], cancel func(error)) {
var idx int64 var idx int64
var total int64 var total int64
for v := range pipe { for v := range pipe {
if reducerPanic && idx == reducerIdx { if reducerPanic && idx == reducerIdx {
panic("baz") panic("baz")
} }
total += v.(int64) total += v
idx++ idx++
} }
writer.Write(total) writer.Write(total)
}, WithWorkers(int(workers)%50+runtime.NumCPU()/2)) }, WithWorkers(workers%50+runtime.NumCPU()))
} }
if genPanic || mapperPanic || reducerPanic { if genPanic || mapperPanic || reducerPanic {
@@ -72,7 +68,7 @@ func FuzzMapReduce(f *testing.F) {
} else { } else {
val, err := fn() val, err := fn()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, squareSum, val.(int64)) assert.Equal(t, squareSum, val)
} }
}) })
} }

View File

@@ -54,28 +54,27 @@ func TestMapReduceRandom(t *testing.T) {
reducerIdx := rand.Int63n(n) reducerIdx := rand.Int63n(n)
squareSum := (n - 1) * n * (2*n - 1) / 6 squareSum := (n - 1) * n * (2*n - 1) / 6
fn := func() (interface{}, error) { fn := func() (int64, error) {
return MapReduce(func(source chan<- interface{}) { return MapReduce(func(source chan<- int64) {
for i := int64(0); i < n; i++ { for i := int64(0); i < n; i++ {
source <- i source <- i
if genPanic && i == genIdx { if genPanic && i == genIdx {
panic("foo") panic("foo")
} }
} }
}, func(item interface{}, writer Writer, cancel func(error)) { }, func(v int64, writer Writer[int64], cancel func(error)) {
v := item.(int64)
if mapperPanic && v == mapperIdx { if mapperPanic && v == mapperIdx {
panic("bar") panic("bar")
} }
writer.Write(v * v) writer.Write(v * v)
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) { }, func(pipe <-chan int64, writer Writer[int64], cancel func(error)) {
var idx int64 var idx int64
var total int64 var total int64
for v := range pipe { for v := range pipe {
if reducerPanic && idx == reducerIdx { if reducerPanic && idx == reducerIdx {
panic("baz") panic("baz")
} }
total += v.(int64) total += v
idx++ idx++
} }
writer.Write(total) writer.Write(total)
@@ -95,7 +94,7 @@ func TestMapReduceRandom(t *testing.T) {
} else { } else {
val, err := fn() val, err := fn()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, squareSum, val.(int64)) assert.Equal(t, squareSum, val)
} }
bar.Increment() bar.Increment()
}) })

View File

@@ -3,7 +3,7 @@ package mr
import ( import (
"context" "context"
"errors" "errors"
"io" "io/ioutil"
"log" "log"
"runtime" "runtime"
"sync/atomic" "sync/atomic"
@@ -17,7 +17,7 @@ import (
var errDummy = errors.New("dummy") var errDummy = errors.New("dummy")
func init() { func init() {
log.SetOutput(io.Discard) log.SetOutput(ioutil.Discard)
} }
func TestFinish(t *testing.T) { func TestFinish(t *testing.T) {
@@ -91,11 +91,11 @@ func TestForEach(t *testing.T) {
defer goleak.VerifyNone(t) defer goleak.VerifyNone(t)
var count uint32 var count uint32
ForEach(func(source chan<- interface{}) { ForEach(func(source chan<- int) {
for i := 0; i < tasks; i++ { for i := 0; i < tasks; i++ {
source <- i source <- i
} }
}, func(item interface{}) { }, func(item int) {
atomic.AddUint32(&count, 1) atomic.AddUint32(&count, 1)
}, WithWorkers(-1)) }, WithWorkers(-1))
@@ -106,12 +106,12 @@ func TestForEach(t *testing.T) {
defer goleak.VerifyNone(t) defer goleak.VerifyNone(t)
var count uint32 var count uint32
ForEach(func(source chan<- interface{}) { ForEach(func(source chan<- int) {
for i := 0; i < tasks; i++ { for i := 0; i < tasks; i++ {
source <- i source <- i
} }
}, func(item interface{}) { }, func(item int) {
if item.(int)%2 == 0 { if item%2 == 0 {
atomic.AddUint32(&count, 1) atomic.AddUint32(&count, 1)
} }
}) })
@@ -123,11 +123,11 @@ func TestForEach(t *testing.T) {
defer goleak.VerifyNone(t) defer goleak.VerifyNone(t)
assert.PanicsWithValue(t, "foo", func() { assert.PanicsWithValue(t, "foo", func() {
ForEach(func(source chan<- interface{}) { ForEach(func(source chan<- int) {
for i := 0; i < tasks; i++ { for i := 0; i < tasks; i++ {
source <- i source <- i
} }
}, func(item interface{}) { }, func(item int) {
panic("foo") panic("foo")
}) })
}) })
@@ -139,9 +139,9 @@ func TestGeneratePanic(t *testing.T) {
t.Run("all", func(t *testing.T) { t.Run("all", func(t *testing.T) {
assert.PanicsWithValue(t, "foo", func() { assert.PanicsWithValue(t, "foo", func() {
ForEach(func(source chan<- interface{}) { ForEach(func(source chan<- int) {
panic("foo") panic("foo")
}, func(item interface{}) { }, func(item int) {
}) })
}) })
}) })
@@ -154,14 +154,14 @@ func TestMapperPanic(t *testing.T) {
var run int32 var run int32
t.Run("all", func(t *testing.T) { t.Run("all", func(t *testing.T) {
assert.PanicsWithValue(t, "foo", func() { assert.PanicsWithValue(t, "foo", func() {
_, _ = MapReduce(func(source chan<- interface{}) { _, _ = MapReduce(func(source chan<- int) {
for i := 0; i < tasks; i++ { for i := 0; i < tasks; i++ {
source <- i source <- i
} }
}, func(item interface{}, writer Writer, cancel func(error)) { }, func(item int, writer Writer[int], cancel func(error)) {
atomic.AddInt32(&run, 1) atomic.AddInt32(&run, 1)
panic("foo") panic("foo")
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) { }, func(pipe <-chan int, writer Writer[int], cancel func(error)) {
}) })
}) })
assert.True(t, atomic.LoadInt32(&run) < tasks/2) assert.True(t, atomic.LoadInt32(&run) < tasks/2)
@@ -173,10 +173,10 @@ func TestMapReduce(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
mapper MapperFunc mapper MapperFunc[int, int]
reducer ReducerFunc reducer ReducerFunc[int, int]
expectErr error expectErr error
expectValue interface{} expectValue int
}{ }{
{ {
name: "simple", name: "simple",
@@ -185,8 +185,7 @@ func TestMapReduce(t *testing.T) {
}, },
{ {
name: "cancel with error", name: "cancel with error",
mapper: func(item interface{}, writer Writer, cancel func(error)) { mapper: func(v int, writer Writer[int], cancel func(error)) {
v := item.(int)
if v%3 == 0 { if v%3 == 0 {
cancel(errDummy) cancel(errDummy)
} }
@@ -196,22 +195,20 @@ func TestMapReduce(t *testing.T) {
}, },
{ {
name: "cancel with nil", name: "cancel with nil",
mapper: func(item interface{}, writer Writer, cancel func(error)) { mapper: func(v int, writer Writer[int], cancel func(error)) {
v := item.(int)
if v%3 == 0 { if v%3 == 0 {
cancel(nil) cancel(nil)
} }
writer.Write(v * v) writer.Write(v * v)
}, },
expectErr: ErrCancelWithNil, expectErr: ErrCancelWithNil,
expectValue: nil,
}, },
{ {
name: "cancel with more", name: "cancel with more",
reducer: func(pipe <-chan interface{}, writer Writer, cancel func(error)) { reducer: func(pipe <-chan int, writer Writer[int], cancel func(error)) {
var result int var result int
for item := range pipe { for item := range pipe {
result += item.(int) result += item
if result > 10 { if result > 10 {
cancel(errDummy) cancel(errDummy)
} }
@@ -226,21 +223,20 @@ func TestMapReduce(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
if test.mapper == nil { if test.mapper == nil {
test.mapper = func(item interface{}, writer Writer, cancel func(error)) { test.mapper = func(v int, writer Writer[int], cancel func(error)) {
v := item.(int)
writer.Write(v * v) writer.Write(v * v)
} }
} }
if test.reducer == nil { if test.reducer == nil {
test.reducer = func(pipe <-chan interface{}, writer Writer, cancel func(error)) { test.reducer = func(pipe <-chan int, writer Writer[int], cancel func(error)) {
var result int var result int
for item := range pipe { for item := range pipe {
result += item.(int) result += item
} }
writer.Write(result) writer.Write(result)
} }
} }
value, err := MapReduce(func(source chan<- interface{}) { value, err := MapReduce(func(source chan<- int) {
for i := 1; i < 5; i++ { for i := 1; i < 5; i++ {
source <- i source <- i
} }
@@ -256,22 +252,21 @@ func TestMapReduce(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
if test.mapper == nil { if test.mapper == nil {
test.mapper = func(item interface{}, writer Writer, cancel func(error)) { test.mapper = func(v int, writer Writer[int], cancel func(error)) {
v := item.(int)
writer.Write(v * v) writer.Write(v * v)
} }
} }
if test.reducer == nil { if test.reducer == nil {
test.reducer = func(pipe <-chan interface{}, writer Writer, cancel func(error)) { test.reducer = func(pipe <-chan int, writer Writer[int], cancel func(error)) {
var result int var result int
for item := range pipe { for item := range pipe {
result += item.(int) result += item
} }
writer.Write(result) writer.Write(result)
} }
} }
source := make(chan interface{}) source := make(chan int)
go func() { go func() {
for i := 1; i < 5; i++ { for i := 1; i < 5; i++ {
source <- i source <- i
@@ -291,13 +286,13 @@ func TestMapReduceWithReduerWriteMoreThanOnce(t *testing.T) {
defer goleak.VerifyNone(t) defer goleak.VerifyNone(t)
assert.Panics(t, func() { assert.Panics(t, func() {
MapReduce(func(source chan<- interface{}) { MapReduce(func(source chan<- int) {
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
source <- i source <- i
} }
}, func(item interface{}, writer Writer, cancel func(error)) { }, func(item int, writer Writer[int], cancel func(error)) {
writer.Write(item) writer.Write(item)
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) { }, func(pipe <-chan int, writer Writer[string], cancel func(error)) {
drain(pipe) drain(pipe)
writer.Write("one") writer.Write("one")
writer.Write("two") writer.Write("two")
@@ -311,8 +306,8 @@ func TestMapReduceVoid(t *testing.T) {
var value uint32 var value uint32
tests := []struct { tests := []struct {
name string name string
mapper MapperFunc mapper MapperFunc[int, int]
reducer VoidReducerFunc reducer VoidReducerFunc[int]
expectValue uint32 expectValue uint32
expectErr error expectErr error
}{ }{
@@ -323,8 +318,7 @@ func TestMapReduceVoid(t *testing.T) {
}, },
{ {
name: "cancel with error", name: "cancel with error",
mapper: func(item interface{}, writer Writer, cancel func(error)) { mapper: func(v int, writer Writer[int], cancel func(error)) {
v := item.(int)
if v%3 == 0 { if v%3 == 0 {
cancel(errDummy) cancel(errDummy)
} }
@@ -334,8 +328,7 @@ func TestMapReduceVoid(t *testing.T) {
}, },
{ {
name: "cancel with nil", name: "cancel with nil",
mapper: func(item interface{}, writer Writer, cancel func(error)) { mapper: func(v int, writer Writer[int], cancel func(error)) {
v := item.(int)
if v%3 == 0 { if v%3 == 0 {
cancel(nil) cancel(nil)
} }
@@ -345,9 +338,9 @@ func TestMapReduceVoid(t *testing.T) {
}, },
{ {
name: "cancel with more", name: "cancel with more",
reducer: func(pipe <-chan interface{}, cancel func(error)) { reducer: func(pipe <-chan int, cancel func(error)) {
for item := range pipe { for item := range pipe {
result := atomic.AddUint32(&value, uint32(item.(int))) result := atomic.AddUint32(&value, uint32(item))
if result > 10 { if result > 10 {
cancel(errDummy) cancel(errDummy)
} }
@@ -362,19 +355,18 @@ func TestMapReduceVoid(t *testing.T) {
atomic.StoreUint32(&value, 0) atomic.StoreUint32(&value, 0)
if test.mapper == nil { if test.mapper == nil {
test.mapper = func(item interface{}, writer Writer, cancel func(error)) { test.mapper = func(v int, writer Writer[int], cancel func(error)) {
v := item.(int)
writer.Write(v * v) writer.Write(v * v)
} }
} }
if test.reducer == nil { if test.reducer == nil {
test.reducer = func(pipe <-chan interface{}, cancel func(error)) { test.reducer = func(pipe <-chan int, cancel func(error)) {
for item := range pipe { for item := range pipe {
atomic.AddUint32(&value, uint32(item.(int))) atomic.AddUint32(&value, uint32(item))
} }
} }
} }
err := MapReduceVoid(func(source chan<- interface{}) { err := MapReduceVoid(func(source chan<- int) {
for i := 1; i < 5; i++ { for i := 1; i < 5; i++ {
source <- i source <- i
} }
@@ -392,18 +384,17 @@ func TestMapReduceVoidWithDelay(t *testing.T) {
defer goleak.VerifyNone(t) defer goleak.VerifyNone(t)
var result []int var result []int
err := MapReduceVoid(func(source chan<- interface{}) { err := MapReduceVoid(func(source chan<- int) {
source <- 0 source <- 0
source <- 1 source <- 1
}, func(item interface{}, writer Writer, cancel func(error)) { }, func(i int, writer Writer[int], cancel func(error)) {
i := item.(int)
if i == 0 { if i == 0 {
time.Sleep(time.Millisecond * 50) time.Sleep(time.Millisecond * 50)
} }
writer.Write(i) writer.Write(i)
}, func(pipe <-chan interface{}, cancel func(error)) { }, func(pipe <-chan int, cancel func(error)) {
for item := range pipe { for item := range pipe {
i := item.(int) i := item
result = append(result, i) result = append(result, i)
} }
}) })
@@ -417,13 +408,12 @@ func TestMapReducePanic(t *testing.T) {
defer goleak.VerifyNone(t) defer goleak.VerifyNone(t)
assert.Panics(t, func() { assert.Panics(t, func() {
_, _ = MapReduce(func(source chan<- interface{}) { _, _ = MapReduce(func(source chan<- int) {
source <- 0 source <- 0
source <- 1 source <- 1
}, func(item interface{}, writer Writer, cancel func(error)) { }, func(i int, writer Writer[int], cancel func(error)) {
i := item.(int)
writer.Write(i) writer.Write(i)
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) { }, func(pipe <-chan int, writer Writer[int], cancel func(error)) {
for range pipe { for range pipe {
panic("panic") panic("panic")
} }
@@ -435,17 +425,16 @@ func TestMapReducePanicOnce(t *testing.T) {
defer goleak.VerifyNone(t) defer goleak.VerifyNone(t)
assert.Panics(t, func() { assert.Panics(t, func() {
_, _ = MapReduce(func(source chan<- interface{}) { _, _ = MapReduce(func(source chan<- int) {
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
source <- i source <- i
} }
}, func(item interface{}, writer Writer, cancel func(error)) { }, func(i int, writer Writer[int], cancel func(error)) {
i := item.(int)
if i == 0 { if i == 0 {
panic("foo") panic("foo")
} }
writer.Write(i) writer.Write(i)
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) { }, func(pipe <-chan int, writer Writer[int], cancel func(error)) {
for range pipe { for range pipe {
panic("bar") panic("bar")
} }
@@ -457,12 +446,12 @@ func TestMapReducePanicBothMapperAndReducer(t *testing.T) {
defer goleak.VerifyNone(t) defer goleak.VerifyNone(t)
assert.Panics(t, func() { assert.Panics(t, func() {
_, _ = MapReduce(func(source chan<- interface{}) { _, _ = MapReduce(func(source chan<- int) {
source <- 0 source <- 0
source <- 1 source <- 1
}, func(item interface{}, writer Writer, cancel func(error)) { }, func(item int, writer Writer[int], cancel func(error)) {
panic("foo") panic("foo")
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) { }, func(pipe <-chan int, writer Writer[int], cancel func(error)) {
panic("bar") panic("bar")
}) })
}) })
@@ -472,18 +461,17 @@ func TestMapReduceVoidCancel(t *testing.T) {
defer goleak.VerifyNone(t) defer goleak.VerifyNone(t)
var result []int var result []int
err := MapReduceVoid(func(source chan<- interface{}) { err := MapReduceVoid(func(source chan<- int) {
source <- 0 source <- 0
source <- 1 source <- 1
}, func(item interface{}, writer Writer, cancel func(error)) { }, func(i int, writer Writer[int], cancel func(error)) {
i := item.(int)
if i == 1 { if i == 1 {
cancel(errors.New("anything")) cancel(errors.New("anything"))
} }
writer.Write(i) writer.Write(i)
}, func(pipe <-chan interface{}, cancel func(error)) { }, func(pipe <-chan int, cancel func(error)) {
for item := range pipe { for item := range pipe {
i := item.(int) i := item
result = append(result, i) result = append(result, i)
} }
}) })
@@ -496,21 +484,19 @@ func TestMapReduceVoidCancelWithRemains(t *testing.T) {
var done int32 var done int32
var result []int var result []int
err := MapReduceVoid(func(source chan<- interface{}) { err := MapReduceVoid(func(source chan<- int) {
for i := 0; i < defaultWorkers*2; i++ { for i := 0; i < defaultWorkers*2; i++ {
source <- i source <- i
} }
atomic.AddInt32(&done, 1) atomic.AddInt32(&done, 1)
}, func(item interface{}, writer Writer, cancel func(error)) { }, func(i int, writer Writer[int], cancel func(error)) {
i := item.(int)
if i == defaultWorkers/2 { if i == defaultWorkers/2 {
cancel(errors.New("anything")) cancel(errors.New("anything"))
} }
writer.Write(i) writer.Write(i)
}, func(pipe <-chan interface{}, cancel func(error)) { }, func(pipe <-chan int, cancel func(error)) {
for item := range pipe { for item := range pipe {
i := item.(int) result = append(result, item)
result = append(result, i)
} }
}) })
assert.NotNil(t, err) assert.NotNil(t, err)
@@ -522,18 +508,18 @@ func TestMapReduceWithoutReducerWrite(t *testing.T) {
defer goleak.VerifyNone(t) defer goleak.VerifyNone(t)
uids := []int{1, 2, 3} uids := []int{1, 2, 3}
res, err := MapReduce(func(source chan<- interface{}) { res, err := MapReduce(func(source chan<- int) {
for _, uid := range uids { for _, uid := range uids {
source <- uid source <- uid
} }
}, func(item interface{}, writer Writer, cancel func(error)) { }, func(item int, writer Writer[int], cancel func(error)) {
writer.Write(item) writer.Write(item)
}, func(pipe <-chan interface{}, writer Writer, cancel func(error)) { }, func(pipe <-chan int, writer Writer[int], cancel func(error)) {
drain(pipe) drain(pipe)
// not calling writer.Write(...), should not panic // not calling writer.Write(...), should not panic
}) })
assert.Equal(t, ErrReduceNoOutput, err) assert.Equal(t, ErrReduceNoOutput, err)
assert.Nil(t, res) assert.Equal(t, 0, res)
} }
func TestMapReduceVoidPanicInReducer(t *testing.T) { func TestMapReduceVoidPanicInReducer(t *testing.T) {
@@ -542,15 +528,14 @@ func TestMapReduceVoidPanicInReducer(t *testing.T) {
const message = "foo" const message = "foo"
assert.Panics(t, func() { assert.Panics(t, func() {
var done int32 var done int32
_ = MapReduceVoid(func(source chan<- interface{}) { _ = MapReduceVoid(func(source chan<- int) {
for i := 0; i < defaultWorkers*2; i++ { for i := 0; i < defaultWorkers*2; i++ {
source <- i source <- i
} }
atomic.AddInt32(&done, 1) atomic.AddInt32(&done, 1)
}, func(item interface{}, writer Writer, cancel func(error)) { }, func(i int, writer Writer[int], cancel func(error)) {
i := item.(int)
writer.Write(i) writer.Write(i)
}, func(pipe <-chan interface{}, cancel func(error)) { }, func(pipe <-chan int, cancel func(error)) {
panic(message) panic(message)
}, WithWorkers(1)) }, WithWorkers(1))
}) })
@@ -561,13 +546,12 @@ func TestForEachWithContext(t *testing.T) {
var done int32 var done int32
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
ForEach(func(source chan<- interface{}) { ForEach(func(source chan<- int) {
for i := 0; i < defaultWorkers*2; i++ { for i := 0; i < defaultWorkers*2; i++ {
source <- i source <- i
} }
atomic.AddInt32(&done, 1) atomic.AddInt32(&done, 1)
}, func(item interface{}) { }, func(i int) {
i := item.(int)
if i == defaultWorkers/2 { if i == defaultWorkers/2 {
cancel() cancel()
} }
@@ -580,20 +564,19 @@ func TestMapReduceWithContext(t *testing.T) {
var done int32 var done int32
var result []int var result []int
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
err := MapReduceVoid(func(source chan<- interface{}) { err := MapReduceVoid(func(source chan<- int) {
for i := 0; i < defaultWorkers*2; i++ { for i := 0; i < defaultWorkers*2; i++ {
source <- i source <- i
} }
atomic.AddInt32(&done, 1) atomic.AddInt32(&done, 1)
}, func(item interface{}, writer Writer, c func(error)) { }, func(i int, writer Writer[int], c func(error)) {
i := item.(int)
if i == defaultWorkers/2 { if i == defaultWorkers/2 {
cancel() cancel()
} }
writer.Write(i) writer.Write(i)
}, func(pipe <-chan interface{}, cancel func(error)) { }, func(pipe <-chan int, cancel func(error)) {
for item := range pipe { for item := range pipe {
i := item.(int) i := item
result = append(result, i) result = append(result, i)
} }
}, WithContext(ctx)) }, WithContext(ctx))
@@ -604,19 +587,19 @@ func TestMapReduceWithContext(t *testing.T) {
func BenchmarkMapReduce(b *testing.B) { func BenchmarkMapReduce(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
mapper := func(v interface{}, writer Writer, cancel func(error)) { mapper := func(v int64, writer Writer[int64], cancel func(error)) {
writer.Write(v.(int64) * v.(int64)) writer.Write(v * v)
} }
reducer := func(input <-chan interface{}, writer Writer, cancel func(error)) { reducer := func(input <-chan int64, writer Writer[int64], cancel func(error)) {
var result int64 var result int64
for v := range input { for v := range input {
result += v.(int64) result += v
} }
writer.Write(result) writer.Write(result)
} }
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
MapReduce(func(input chan<- interface{}) { MapReduce(func(input chan<- int64) {
for j := 0; j < 2; j++ { for j := 0; j < 2; j++ {
input <- int64(j) input <- int64(j)
} }

View File

@@ -58,20 +58,19 @@ import (
) )
func main() { func main() {
val, err := mr.MapReduce(func(source chan<- interface{}) { val, err := mr.MapReduce(func(source chan<- int) {
// generator // generator
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
source <- i source <- i
} }
}, func(item interface{}, writer mr.Writer, cancel func(error)) { }, func(i int, writer mr.Writer[int], cancel func(error)) {
// mapper // mapper
i := item.(int)
writer.Write(i * i) writer.Write(i * i)
}, func(pipe <-chan interface{}, writer mr.Writer, cancel func(error)) { }, func(pipe <-chan int, writer mr.Writer[int], cancel func(error)) {
// reducer // reducer
var sum int var sum int
for i := range pipe { for i := range pipe {
sum += i.(int) sum += i
} }
writer.Write(sum) writer.Write(sum)
}) })

View File

@@ -59,20 +59,19 @@ import (
) )
func main() { func main() {
val, err := mr.MapReduce(func(source chan<- interface{}) { val, err := mr.MapReduce(func(source chan<- int) {
// generator // generator
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
source <- i source <- i
} }
}, func(item interface{}, writer mr.Writer, cancel func(error)) { }, func(i int, writer mr.Writer[int], cancel func(error)) {
// mapper // mapper
i := item.(int)
writer.Write(i * i) writer.Write(i * i)
}, func(pipe <-chan interface{}, writer mr.Writer, cancel func(error)) { }, func(pipe <-chan int, writer mr.Writer[int], cancel func(error)) {
// reducer // reducer
var sum int var sum int
for i := range pipe { for i := range pipe {
sum += i.(int) sum += i
} }
writer.Write(sum) writer.Write(sum)
}) })

View File

@@ -15,5 +15,14 @@ func AddWrapUpListener(fn func()) func() {
return fn return fn
} }
// SetTimeToForceQuit does nothing on windows.
func SetTimeToForceQuit(duration time.Duration) { func SetTimeToForceQuit(duration time.Duration) {
} }
// Shutdown does nothing on windows.
func Shutdown() {
}
// WrapUp does nothing on windows.
func WrapUp() {
}

View File

@@ -43,6 +43,16 @@ func SetTimeToForceQuit(duration time.Duration) {
delayTimeBeforeForceQuit = duration delayTimeBeforeForceQuit = duration
} }
// Shutdown calls the registered shutdown listeners, only for test purpose.
func Shutdown() {
shutdownListeners.notifyListeners()
}
// WrapUp wraps up the process, only for test purpose.
func WrapUp() {
wrapUpListeners.notifyListeners()
}
func gracefulStop(signals chan os.Signal) { func gracefulStop(signals chan os.Signal) {
signal.Stop(signals) signal.Stop(signals)

View File

@@ -18,14 +18,14 @@ func TestShutdown(t *testing.T) {
called := AddWrapUpListener(func() { called := AddWrapUpListener(func() {
val++ val++
}) })
wrapUpListeners.notifyListeners() WrapUp()
called() called()
assert.Equal(t, 1, val) assert.Equal(t, 1, val)
called = AddShutdownListener(func() { called = AddShutdownListener(func() {
val += 2 val += 2
}) })
shutdownListeners.notifyListeners() Shutdown()
called() called()
assert.Equal(t, 3, val) assert.Equal(t, 3, val)
} }

View File

@@ -4,7 +4,7 @@ type (
// A Consumer interface represents a consumer that can consume string messages. // A Consumer interface represents a consumer that can consume string messages.
Consumer interface { Consumer interface {
Consume(string) error Consume(string) error
OnEvent(event interface{}) OnEvent(event any)
} }
// ConsumerFactory defines the factory to generate consumers. // ConsumerFactory defines the factory to generate consumers.

View File

@@ -31,7 +31,7 @@ type (
quit chan struct{} quit chan struct{}
listeners []Listener listeners []Listener
eventLock sync.Mutex eventLock sync.Mutex
eventChannels []chan interface{} eventChannels []chan any
} }
// A Listener interface represents a listener that can be notified with queue events. // A Listener interface represents a listener that can be notified with queue events.
@@ -77,7 +77,7 @@ func (q *Queue) AddListener(listener Listener) {
} }
// Broadcast broadcasts message to all event channels. // Broadcast broadcasts message to all event channels.
func (q *Queue) Broadcast(message interface{}) { func (q *Queue) Broadcast(message any) {
go func() { go func() {
q.eventLock.Lock() q.eventLock.Lock()
defer q.eventLock.Unlock() defer q.eventLock.Unlock()
@@ -119,7 +119,7 @@ func (q *Queue) Stop() {
close(q.quit) close(q.quit)
} }
func (q *Queue) consume(eventChan chan interface{}) { func (q *Queue) consume(eventChan chan any) {
var consumer Consumer var consumer Consumer
for { for {
@@ -216,7 +216,7 @@ func (q *Queue) resume() {
func (q *Queue) startConsumers(number int) { func (q *Queue) startConsumers(number int) {
for i := 0; i < number; i++ { for i := 0; i < number; i++ {
eventChan := make(chan interface{}) eventChan := make(chan any)
q.eventLock.Lock() q.eventLock.Lock()
q.eventChannels = append(q.eventChannels, eventChan) q.eventChannels = append(q.eventChannels, eventChan)
q.eventLock.Unlock() q.eventLock.Unlock()

View File

@@ -52,7 +52,7 @@ func (c *mockedConsumer) Consume(string) error {
return nil return nil
} }
func (c *mockedConsumer) OnEvent(interface{}) { func (c *mockedConsumer) OnEvent(any) {
if atomic.AddInt32(&c.events, 1) <= consumers { if atomic.AddInt32(&c.events, 1) <= consumers {
c.wait.Done() c.wait.Done()
} }

View File

@@ -35,7 +35,7 @@ type (
} }
node struct { node struct {
item interface{} item any
children [2]map[string]*node children [2]map[string]*node
} }
@@ -46,7 +46,7 @@ type (
// A Result is a search result from tree. // A Result is a search result from tree.
Result struct { Result struct {
Item interface{} Item any
Params map[string]string Params map[string]string
} }
) )
@@ -59,7 +59,7 @@ func NewTree() *Tree {
} }
// Add adds item to associate with route. // Add adds item to associate with route.
func (t *Tree) Add(route string, item interface{}) error { func (t *Tree) Add(route string, item any) error {
if len(route) == 0 || route[0] != slash { if len(route) == 0 || route[0] != slash {
return errNotFromRoot return errNotFromRoot
} }
@@ -149,7 +149,7 @@ func (nd *node) getChildren(route string) map[string]*node {
return nd.children[0] return nd.children[0]
} }
func add(nd *node, route string, item interface{}) error { func add(nd *node, route string, item any) error {
if len(route) == 0 { if len(route) == 0 {
if nd.item != nil { if nd.item != nil {
return errDupItem return errDupItem
@@ -228,7 +228,7 @@ func match(pat, token string) innerResult {
} }
} }
func newNode(item interface{}) *node { func newNode(item any) *node {
return &node{ return &node{
item: item, item: item,
children: [2]map[string]*node{ children: [2]map[string]*node{

View File

@@ -3,6 +3,7 @@ package service
import ( import (
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
) )
@@ -16,3 +17,15 @@ func TestServiceConf(t *testing.T) {
} }
c.MustSetUp() c.MustSetUp()
} }
func TestServiceConfWithMetricsUrl(t *testing.T) {
c := ServiceConf{
Name: "foo",
Log: logx.LogConf{
Mode: "volume",
},
Mode: "dev",
MetricsUrl: "http://localhost:8080",
}
assert.NoError(t, c.SetUp())
}

View File

@@ -5,6 +5,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/proc"
) )
var ( var (
@@ -55,6 +56,7 @@ func TestServiceGroup(t *testing.T) {
} }
group.Stop() group.Stop()
proc.Shutdown()
mutex.Lock() mutex.Lock()
defer mutex.Unlock() defer mutex.Unlock()

View File

@@ -104,7 +104,7 @@ type (
} }
) )
func (c *metricsContainer) AddTask(v interface{}) bool { func (c *metricsContainer) AddTask(v any) bool {
if task, ok := v.(Task); ok { if task, ok := v.(Task); ok {
if task.Drop { if task.Drop {
c.drops++ c.drops++
@@ -117,7 +117,7 @@ func (c *metricsContainer) AddTask(v interface{}) bool {
return false return false
} }
func (c *metricsContainer) Execute(v interface{}) { func (c *metricsContainer) Execute(v any) {
pair := v.(tasksDurationPair) pair := v.(tasksDurationPair)
tasks := pair.tasks tasks := pair.tasks
duration := pair.duration duration := pair.duration
@@ -180,7 +180,7 @@ func (c *metricsContainer) Execute(v interface{}) {
log(report) log(report)
} }
func (c *metricsContainer) RemoveAll() interface{} { func (c *metricsContainer) RemoveAll() any {
tasks := c.tasks tasks := c.tasks
duration := c.duration duration := c.duration
drops := c.drops drops := c.drops

View File

@@ -16,11 +16,11 @@ func (h *taskHeap) Swap(i, j int) {
(*h)[i], (*h)[j] = (*h)[j], (*h)[i] (*h)[i], (*h)[j] = (*h)[j], (*h)[i]
} }
func (h *taskHeap) Push(x interface{}) { func (h *taskHeap) Push(x any) {
*h = append(*h, x.(Task)) *h = append(*h, x.(Task))
} }
func (h *taskHeap) Pop() interface{} { func (h *taskHeap) Pop() any {
old := *h old := *h
n := len(old) n := len(old)
x := old[n-1] x := old[n-1]

View File

@@ -9,7 +9,7 @@ import (
const dbTag = "db" const dbTag = "db"
// RawFieldNames converts golang struct field into slice string. // RawFieldNames converts golang struct field into slice string.
func RawFieldNames(in interface{}, postgresSql ...bool) []string { func RawFieldNames(in any, postgresSql ...bool) []string {
out := make([]string, 0) out := make([]string, 0)
v := reflect.ValueOf(in) v := reflect.ValueOf(in)
if v.Kind() == reflect.Ptr { if v.Kind() == reflect.Ptr {

View File

@@ -9,6 +9,7 @@ import (
"github.com/zeromicro/go-zero/core/errorx" "github.com/zeromicro/go-zero/core/errorx"
"github.com/zeromicro/go-zero/core/hash" "github.com/zeromicro/go-zero/core/hash"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/core/syncx" "github.com/zeromicro/go-zero/core/syncx"
) )
@@ -20,32 +21,32 @@ type (
// DelCtx deletes cached values with keys. // DelCtx deletes cached values with keys.
DelCtx(ctx context.Context, keys ...string) error DelCtx(ctx context.Context, keys ...string) error
// Get gets the cache with key and fills into v. // Get gets the cache with key and fills into v.
Get(key string, val interface{}) error Get(key string, val any) error
// GetCtx gets the cache with key and fills into v. // GetCtx gets the cache with key and fills into v.
GetCtx(ctx context.Context, key string, val interface{}) error GetCtx(ctx context.Context, key string, val any) error
// IsNotFound checks if the given error is the defined errNotFound. // IsNotFound checks if the given error is the defined errNotFound.
IsNotFound(err error) bool IsNotFound(err error) bool
// Set sets the cache with key and v, using c.expiry. // Set sets the cache with key and v, using c.expiry.
Set(key string, val interface{}) error Set(key string, val any) error
// SetCtx sets the cache with key and v, using c.expiry. // SetCtx sets the cache with key and v, using c.expiry.
SetCtx(ctx context.Context, key string, val interface{}) error SetCtx(ctx context.Context, key string, val any) error
// SetWithExpire sets the cache with key and v, using given expire. // SetWithExpire sets the cache with key and v, using given expire.
SetWithExpire(key string, val interface{}, expire time.Duration) error SetWithExpire(key string, val any, expire time.Duration) error
// SetWithExpireCtx sets the cache with key and v, using given expire. // SetWithExpireCtx sets the cache with key and v, using given expire.
SetWithExpireCtx(ctx context.Context, key string, val interface{}, expire time.Duration) error SetWithExpireCtx(ctx context.Context, key string, val any, expire time.Duration) error
// Take takes the result from cache first, if not found, // Take takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result. // query from DB and set cache using c.expiry, then return the result.
Take(val interface{}, key string, query func(val interface{}) error) error Take(val any, key string, query func(val any) error) error
// TakeCtx takes the result from cache first, if not found, // TakeCtx takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result. // query from DB and set cache using c.expiry, then return the result.
TakeCtx(ctx context.Context, val interface{}, key string, query func(val interface{}) error) error TakeCtx(ctx context.Context, val any, key string, query func(val any) error) error
// TakeWithExpire takes the result from cache first, if not found, // TakeWithExpire takes the result from cache first, if not found,
// query from DB and set cache using given expire, then return the result. // query from DB and set cache using given expire, then return the result.
TakeWithExpire(val interface{}, key string, query func(val interface{}, expire time.Duration) error) error TakeWithExpire(val any, key string, query func(val any, expire time.Duration) error) error
// TakeWithExpireCtx takes the result from cache first, if not found, // TakeWithExpireCtx takes the result from cache first, if not found,
// query from DB and set cache using given expire, then return the result. // query from DB and set cache using given expire, then return the result.
TakeWithExpireCtx(ctx context.Context, val interface{}, key string, TakeWithExpireCtx(ctx context.Context, val any, key string,
query func(val interface{}, expire time.Duration) error) error query func(val any, expire time.Duration) error) error
} }
cacheCluster struct { cacheCluster struct {
@@ -62,12 +63,12 @@ func New(c ClusterConf, barrier syncx.SingleFlight, st *Stat, errNotFound error,
} }
if len(c) == 1 { if len(c) == 1 {
return NewNode(c[0].NewRedis(), barrier, st, errNotFound, opts...) return NewNode(redis.MustNewRedis(c[0].RedisConf), barrier, st, errNotFound, opts...)
} }
dispatcher := hash.NewConsistentHash() dispatcher := hash.NewConsistentHash()
for _, node := range c { for _, node := range c {
cn := NewNode(node.NewRedis(), barrier, st, errNotFound, opts...) cn := NewNode(redis.MustNewRedis(node.RedisConf), barrier, st, errNotFound, opts...)
dispatcher.AddWithWeight(cn, node.Weight) dispatcher.AddWithWeight(cn, node.Weight)
} }
@@ -97,7 +98,7 @@ func (cc cacheCluster) DelCtx(ctx context.Context, keys ...string) error {
return c.(Cache).DelCtx(ctx, key) return c.(Cache).DelCtx(ctx, key)
default: default:
var be errorx.BatchError var be errorx.BatchError
nodes := make(map[interface{}][]string) nodes := make(map[any][]string)
for _, key := range keys { for _, key := range keys {
c, ok := cc.dispatcher.Get(key) c, ok := cc.dispatcher.Get(key)
if !ok { if !ok {
@@ -118,12 +119,12 @@ func (cc cacheCluster) DelCtx(ctx context.Context, keys ...string) error {
} }
// Get gets the cache with key and fills into v. // Get gets the cache with key and fills into v.
func (cc cacheCluster) Get(key string, val interface{}) error { func (cc cacheCluster) Get(key string, val any) error {
return cc.GetCtx(context.Background(), key, val) return cc.GetCtx(context.Background(), key, val)
} }
// GetCtx gets the cache with key and fills into v. // GetCtx gets the cache with key and fills into v.
func (cc cacheCluster) GetCtx(ctx context.Context, key string, val interface{}) error { func (cc cacheCluster) GetCtx(ctx context.Context, key string, val any) error {
c, ok := cc.dispatcher.Get(key) c, ok := cc.dispatcher.Get(key)
if !ok { if !ok {
return cc.errNotFound return cc.errNotFound
@@ -138,12 +139,12 @@ func (cc cacheCluster) IsNotFound(err error) bool {
} }
// Set sets the cache with key and v, using c.expiry. // Set sets the cache with key and v, using c.expiry.
func (cc cacheCluster) Set(key string, val interface{}) error { func (cc cacheCluster) Set(key string, val any) error {
return cc.SetCtx(context.Background(), key, val) return cc.SetCtx(context.Background(), key, val)
} }
// SetCtx sets the cache with key and v, using c.expiry. // SetCtx sets the cache with key and v, using c.expiry.
func (cc cacheCluster) SetCtx(ctx context.Context, key string, val interface{}) error { func (cc cacheCluster) SetCtx(ctx context.Context, key string, val any) error {
c, ok := cc.dispatcher.Get(key) c, ok := cc.dispatcher.Get(key)
if !ok { if !ok {
return cc.errNotFound return cc.errNotFound
@@ -153,12 +154,12 @@ func (cc cacheCluster) SetCtx(ctx context.Context, key string, val interface{})
} }
// SetWithExpire sets the cache with key and v, using given expire. // SetWithExpire sets the cache with key and v, using given expire.
func (cc cacheCluster) SetWithExpire(key string, val interface{}, expire time.Duration) error { func (cc cacheCluster) SetWithExpire(key string, val any, expire time.Duration) error {
return cc.SetWithExpireCtx(context.Background(), key, val, expire) return cc.SetWithExpireCtx(context.Background(), key, val, expire)
} }
// SetWithExpireCtx sets the cache with key and v, using given expire. // SetWithExpireCtx sets the cache with key and v, using given expire.
func (cc cacheCluster) SetWithExpireCtx(ctx context.Context, key string, val interface{}, expire time.Duration) error { func (cc cacheCluster) SetWithExpireCtx(ctx context.Context, key string, val any, expire time.Duration) error {
c, ok := cc.dispatcher.Get(key) c, ok := cc.dispatcher.Get(key)
if !ok { if !ok {
return cc.errNotFound return cc.errNotFound
@@ -169,13 +170,13 @@ func (cc cacheCluster) SetWithExpireCtx(ctx context.Context, key string, val int
// Take takes the result from cache first, if not found, // Take takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result. // query from DB and set cache using c.expiry, then return the result.
func (cc cacheCluster) Take(val interface{}, key string, query func(val interface{}) error) error { func (cc cacheCluster) Take(val any, key string, query func(val any) error) error {
return cc.TakeCtx(context.Background(), val, key, query) return cc.TakeCtx(context.Background(), val, key, query)
} }
// TakeCtx takes the result from cache first, if not found, // TakeCtx takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result. // query from DB and set cache using c.expiry, then return the result.
func (cc cacheCluster) TakeCtx(ctx context.Context, val interface{}, key string, query func(val interface{}) error) error { func (cc cacheCluster) TakeCtx(ctx context.Context, val any, key string, query func(val any) error) error {
c, ok := cc.dispatcher.Get(key) c, ok := cc.dispatcher.Get(key)
if !ok { if !ok {
return cc.errNotFound return cc.errNotFound
@@ -186,13 +187,13 @@ func (cc cacheCluster) TakeCtx(ctx context.Context, val interface{}, key string,
// TakeWithExpire takes the result from cache first, if not found, // TakeWithExpire takes the result from cache first, if not found,
// query from DB and set cache using given expire, then return the result. // query from DB and set cache using given expire, then return the result.
func (cc cacheCluster) TakeWithExpire(val interface{}, key string, query func(val interface{}, expire time.Duration) error) error { func (cc cacheCluster) TakeWithExpire(val any, key string, query func(val any, expire time.Duration) error) error {
return cc.TakeWithExpireCtx(context.Background(), val, key, query) return cc.TakeWithExpireCtx(context.Background(), val, key, query)
} }
// TakeWithExpireCtx takes the result from cache first, if not found, // TakeWithExpireCtx takes the result from cache first, if not found,
// query from DB and set cache using given expire, then return the result. // query from DB and set cache using given expire, then return the result.
func (cc cacheCluster) TakeWithExpireCtx(ctx context.Context, val interface{}, key string, query func(val interface{}, expire time.Duration) error) error { func (cc cacheCluster) TakeWithExpireCtx(ctx context.Context, val any, key string, query func(val any, expire time.Duration) error) error {
c, ok := cc.dispatcher.Get(key) c, ok := cc.dispatcher.Get(key)
if !ok { if !ok {
return cc.errNotFound return cc.errNotFound

View File

@@ -44,11 +44,11 @@ func (mc *mockedNode) DelCtx(_ context.Context, keys ...string) error {
return be.Err() return be.Err()
} }
func (mc *mockedNode) Get(key string, val interface{}) error { func (mc *mockedNode) Get(key string, val any) error {
return mc.GetCtx(context.Background(), key, val) return mc.GetCtx(context.Background(), key, val)
} }
func (mc *mockedNode) GetCtx(ctx context.Context, key string, val interface{}) error { func (mc *mockedNode) GetCtx(ctx context.Context, key string, val any) error {
bs, ok := mc.vals[key] bs, ok := mc.vals[key]
if ok { if ok {
return json.Unmarshal(bs, val) return json.Unmarshal(bs, val)
@@ -61,11 +61,11 @@ func (mc *mockedNode) IsNotFound(err error) bool {
return errors.Is(err, mc.errNotFound) return errors.Is(err, mc.errNotFound)
} }
func (mc *mockedNode) Set(key string, val interface{}) error { func (mc *mockedNode) Set(key string, val any) error {
return mc.SetCtx(context.Background(), key, val) return mc.SetCtx(context.Background(), key, val)
} }
func (mc *mockedNode) SetCtx(ctx context.Context, key string, val interface{}) error { func (mc *mockedNode) SetCtx(ctx context.Context, key string, val any) error {
data, err := json.Marshal(val) data, err := json.Marshal(val)
if err != nil { if err != nil {
return err return err
@@ -75,19 +75,19 @@ func (mc *mockedNode) SetCtx(ctx context.Context, key string, val interface{}) e
return nil return nil
} }
func (mc *mockedNode) SetWithExpire(key string, val interface{}, expire time.Duration) error { func (mc *mockedNode) SetWithExpire(key string, val any, expire time.Duration) error {
return mc.SetWithExpireCtx(context.Background(), key, val, expire) return mc.SetWithExpireCtx(context.Background(), key, val, expire)
} }
func (mc *mockedNode) SetWithExpireCtx(ctx context.Context, key string, val interface{}, expire time.Duration) error { func (mc *mockedNode) SetWithExpireCtx(ctx context.Context, key string, val any, expire time.Duration) error {
return mc.Set(key, val) return mc.Set(key, val)
} }
func (mc *mockedNode) Take(val interface{}, key string, query func(val interface{}) error) error { func (mc *mockedNode) Take(val any, key string, query func(val any) error) error {
return mc.TakeCtx(context.Background(), val, key, query) return mc.TakeCtx(context.Background(), val, key, query)
} }
func (mc *mockedNode) TakeCtx(ctx context.Context, val interface{}, key string, query func(val interface{}) error) error { func (mc *mockedNode) TakeCtx(ctx context.Context, val any, key string, query func(val any) error) error {
if _, ok := mc.vals[key]; ok { if _, ok := mc.vals[key]; ok {
return mc.GetCtx(ctx, key, val) return mc.GetCtx(ctx, key, val)
} }
@@ -99,12 +99,12 @@ func (mc *mockedNode) TakeCtx(ctx context.Context, val interface{}, key string,
return mc.SetCtx(ctx, key, val) return mc.SetCtx(ctx, key, val)
} }
func (mc *mockedNode) TakeWithExpire(val interface{}, key string, query func(val interface{}, expire time.Duration) error) error { func (mc *mockedNode) TakeWithExpire(val any, key string, query func(val any, expire time.Duration) error) error {
return mc.TakeWithExpireCtx(context.Background(), val, key, query) return mc.TakeWithExpireCtx(context.Background(), val, key, query)
} }
func (mc *mockedNode) TakeWithExpireCtx(ctx context.Context, val interface{}, key string, query func(val interface{}, expire time.Duration) error) error { func (mc *mockedNode) TakeWithExpireCtx(ctx context.Context, val any, key string, query func(val any, expire time.Duration) error) error {
return mc.Take(val, key, func(val interface{}) error { return mc.Take(val, key, func(val any) error {
return query(val, 0) return query(val, 0)
}) })
} }
@@ -163,12 +163,10 @@ func TestCache_SetDel(t *testing.T) {
r1, err := miniredis.Run() r1, err := miniredis.Run()
assert.NoError(t, err) assert.NoError(t, err)
defer r1.Close() defer r1.Close()
r1.SetError("mock error")
r2, err := miniredis.Run() r2, err := miniredis.Run()
assert.NoError(t, err) assert.NoError(t, err)
defer r2.Close() defer r2.Close()
r2.SetError("mock error")
conf := ClusterConf{ conf := ClusterConf{
{ {
@@ -187,6 +185,8 @@ func TestCache_SetDel(t *testing.T) {
}, },
} }
c := New(conf, syncx.NewSingleFlight(), NewStat("mock"), errPlaceholder) c := New(conf, syncx.NewSingleFlight(), NewStat("mock"), errPlaceholder)
r1.SetError("mock error")
r2.SetError("mock error")
assert.NoError(t, c.Del("a", "b", "c")) assert.NoError(t, c.Del("a", "b", "c"))
}) })
} }
@@ -279,13 +279,13 @@ func TestCache_Balance(t *testing.T) {
for i := 0; i < total/10; i++ { for i := 0; i < total/10; i++ {
var val int var val int
if i%2 == 0 { if i%2 == 0 {
assert.Nil(t, c.Take(&val, strconv.Itoa(i*10), func(val interface{}) error { assert.Nil(t, c.Take(&val, strconv.Itoa(i*10), func(val any) error {
*val.(*int) = i *val.(*int) = i
count++ count++
return nil return nil
})) }))
} else { } else {
assert.Nil(t, c.TakeWithExpire(&val, strconv.Itoa(i*10), func(val interface{}, expire time.Duration) error { assert.Nil(t, c.TakeWithExpire(&val, strconv.Itoa(i*10), func(val any, expire time.Duration) error {
*val.(*int) = i *val.(*int) = i
count++ count++
return nil return nil
@@ -307,10 +307,10 @@ func TestCacheNoNode(t *testing.T) {
assert.NotNil(t, c.Get("foo", nil)) assert.NotNil(t, c.Get("foo", nil))
assert.NotNil(t, c.Set("foo", nil)) assert.NotNil(t, c.Set("foo", nil))
assert.NotNil(t, c.SetWithExpire("foo", nil, time.Second)) assert.NotNil(t, c.SetWithExpire("foo", nil, time.Second))
assert.NotNil(t, c.Take(nil, "foo", func(val interface{}) error { assert.NotNil(t, c.Take(nil, "foo", func(val any) error {
return nil return nil
})) }))
assert.NotNil(t, c.TakeWithExpire(nil, "foo", func(val interface{}, duration time.Duration) error { assert.NotNil(t, c.TakeWithExpire(nil, "foo", func(val any, duration time.Duration) error {
return nil return nil
})) }))
} }

View File

@@ -89,12 +89,12 @@ func (c cacheNode) DelCtx(ctx context.Context, keys ...string) error {
} }
// Get gets the cache with key and fills into v. // Get gets the cache with key and fills into v.
func (c cacheNode) Get(key string, val interface{}) error { func (c cacheNode) Get(key string, val any) error {
return c.GetCtx(context.Background(), key, val) return c.GetCtx(context.Background(), key, val)
} }
// GetCtx gets the cache with key and fills into v. // GetCtx gets the cache with key and fills into v.
func (c cacheNode) GetCtx(ctx context.Context, key string, val interface{}) error { func (c cacheNode) GetCtx(ctx context.Context, key string, val any) error {
err := c.doGetCache(ctx, key, val) err := c.doGetCache(ctx, key, val)
if err == errPlaceholder { if err == errPlaceholder {
return c.errNotFound return c.errNotFound
@@ -109,22 +109,22 @@ func (c cacheNode) IsNotFound(err error) bool {
} }
// Set sets the cache with key and v, using c.expiry. // Set sets the cache with key and v, using c.expiry.
func (c cacheNode) Set(key string, val interface{}) error { func (c cacheNode) Set(key string, val any) error {
return c.SetCtx(context.Background(), key, val) return c.SetCtx(context.Background(), key, val)
} }
// SetCtx sets the cache with key and v, using c.expiry. // SetCtx sets the cache with key and v, using c.expiry.
func (c cacheNode) SetCtx(ctx context.Context, key string, val interface{}) error { func (c cacheNode) SetCtx(ctx context.Context, key string, val any) error {
return c.SetWithExpireCtx(ctx, key, val, c.aroundDuration(c.expiry)) return c.SetWithExpireCtx(ctx, key, val, c.aroundDuration(c.expiry))
} }
// SetWithExpire sets the cache with key and v, using given expire. // SetWithExpire sets the cache with key and v, using given expire.
func (c cacheNode) SetWithExpire(key string, val interface{}, expire time.Duration) error { func (c cacheNode) SetWithExpire(key string, val any, expire time.Duration) error {
return c.SetWithExpireCtx(context.Background(), key, val, expire) return c.SetWithExpireCtx(context.Background(), key, val, expire)
} }
// SetWithExpireCtx sets the cache with key and v, using given expire. // SetWithExpireCtx sets the cache with key and v, using given expire.
func (c cacheNode) SetWithExpireCtx(ctx context.Context, key string, val interface{}, func (c cacheNode) SetWithExpireCtx(ctx context.Context, key string, val any,
expire time.Duration) error { expire time.Duration) error {
data, err := jsonx.Marshal(val) data, err := jsonx.Marshal(val)
if err != nil { if err != nil {
@@ -141,34 +141,34 @@ func (c cacheNode) String() string {
// Take takes the result from cache first, if not found, // Take takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result. // query from DB and set cache using c.expiry, then return the result.
func (c cacheNode) Take(val interface{}, key string, query func(val interface{}) error) error { func (c cacheNode) Take(val any, key string, query func(val any) error) error {
return c.TakeCtx(context.Background(), val, key, query) return c.TakeCtx(context.Background(), val, key, query)
} }
// TakeCtx takes the result from cache first, if not found, // TakeCtx takes the result from cache first, if not found,
// query from DB and set cache using c.expiry, then return the result. // query from DB and set cache using c.expiry, then return the result.
func (c cacheNode) TakeCtx(ctx context.Context, val interface{}, key string, func (c cacheNode) TakeCtx(ctx context.Context, val any, key string,
query func(val interface{}) error) error { query func(val any) error) error {
return c.doTake(ctx, val, key, query, func(v interface{}) error { return c.doTake(ctx, val, key, query, func(v any) error {
return c.SetCtx(ctx, key, v) return c.SetCtx(ctx, key, v)
}) })
} }
// TakeWithExpire takes the result from cache first, if not found, // TakeWithExpire takes the result from cache first, if not found,
// query from DB and set cache using given expire, then return the result. // query from DB and set cache using given expire, then return the result.
func (c cacheNode) TakeWithExpire(val interface{}, key string, query func(val interface{}, func (c cacheNode) TakeWithExpire(val any, key string, query func(val any,
expire time.Duration) error) error { expire time.Duration) error) error {
return c.TakeWithExpireCtx(context.Background(), val, key, query) return c.TakeWithExpireCtx(context.Background(), val, key, query)
} }
// TakeWithExpireCtx takes the result from cache first, if not found, // TakeWithExpireCtx takes the result from cache first, if not found,
// query from DB and set cache using given expire, then return the result. // query from DB and set cache using given expire, then return the result.
func (c cacheNode) TakeWithExpireCtx(ctx context.Context, val interface{}, key string, func (c cacheNode) TakeWithExpireCtx(ctx context.Context, val any, key string,
query func(val interface{}, expire time.Duration) error) error { query func(val any, expire time.Duration) error) error {
expire := c.aroundDuration(c.expiry) expire := c.aroundDuration(c.expiry)
return c.doTake(ctx, val, key, func(v interface{}) error { return c.doTake(ctx, val, key, func(v any) error {
return query(v, expire) return query(v, expire)
}, func(v interface{}) error { }, func(v any) error {
return c.SetWithExpireCtx(ctx, key, v, expire) return c.SetWithExpireCtx(ctx, key, v, expire)
}) })
} }
@@ -184,7 +184,7 @@ func (c cacheNode) asyncRetryDelCache(keys ...string) {
}, keys...) }, keys...)
} }
func (c cacheNode) doGetCache(ctx context.Context, key string, v interface{}) error { func (c cacheNode) doGetCache(ctx context.Context, key string, v any) error {
c.stat.IncrementTotal() c.stat.IncrementTotal()
data, err := c.rds.GetCtx(ctx, key) data, err := c.rds.GetCtx(ctx, key)
if err != nil { if err != nil {
@@ -205,10 +205,10 @@ func (c cacheNode) doGetCache(ctx context.Context, key string, v interface{}) er
return c.processCache(ctx, key, data, v) return c.processCache(ctx, key, data, v)
} }
func (c cacheNode) doTake(ctx context.Context, v interface{}, key string, func (c cacheNode) doTake(ctx context.Context, v any, key string,
query func(v interface{}) error, cacheVal func(v interface{}) error) error { query func(v any) error, cacheVal func(v any) error) error {
logger := logx.WithContext(ctx) logger := logx.WithContext(ctx)
val, fresh, err := c.barrier.DoEx(key, func() (interface{}, error) { val, fresh, err := c.barrier.DoEx(key, func() (any, error) {
if err := c.doGetCache(ctx, key, v); err != nil { if err := c.doGetCache(ctx, key, v); err != nil {
if err == errPlaceholder { if err == errPlaceholder {
return nil, c.errNotFound return nil, c.errNotFound
@@ -255,7 +255,7 @@ func (c cacheNode) doTake(ctx context.Context, v interface{}, key string,
return jsonx.Unmarshal(val.([]byte), v) return jsonx.Unmarshal(val.([]byte), v)
} }
func (c cacheNode) processCache(ctx context.Context, key, data string, v interface{}) error { func (c cacheNode) processCache(ctx context.Context, key, data string, v any) error {
err := jsonx.Unmarshal([]byte(data), v) err := jsonx.Unmarshal([]byte(data), v)
if err == nil { if err == nil {
return nil return nil
@@ -277,5 +277,6 @@ func (c cacheNode) processCache(ctx context.Context, key, data string, v interfa
func (c cacheNode) setCacheWithNotFound(ctx context.Context, key string) error { func (c cacheNode) setCacheWithNotFound(ctx context.Context, key string) error {
seconds := int(math.Ceil(c.aroundDuration(c.notFoundExpiry).Seconds())) seconds := int(math.Ceil(c.aroundDuration(c.notFoundExpiry).Seconds()))
return c.rds.SetexCtx(ctx, key, notFoundPlaceholder, seconds) _, err := c.rds.SetnxExCtx(ctx, key, notFoundPlaceholder, seconds)
return err
} }

View File

@@ -1,3 +1,6 @@
//go:build !race
// Disable data race detection is because of the timingWheel in cacheNode.
package cache package cache
import ( import (
@@ -59,7 +62,7 @@ func TestCacheNode_DelCache(t *testing.T) {
ticker := timex.NewFakeTicker() ticker := timex.NewFakeTicker()
var err error var err error
timingWheel, err = collection.NewTimingWheelWithTicker( timingWheel, err = collection.NewTimingWheelWithTicker(
time.Millisecond, timingWheelSlots, func(key, value interface{}) { time.Millisecond, timingWheelSlots, func(key, value any) {
clean(key, value) clean(key, value)
}, ticker) }, ticker)
assert.NoError(t, err) assert.NoError(t, err)
@@ -143,7 +146,7 @@ func TestCacheNode_Take(t *testing.T) {
cn := NewNode(store, syncx.NewSingleFlight(), NewStat("any"), errTestNotFound, cn := NewNode(store, syncx.NewSingleFlight(), NewStat("any"), errTestNotFound,
WithExpiry(time.Second), WithNotFoundExpiry(time.Second)) WithExpiry(time.Second), WithNotFoundExpiry(time.Second))
var str string var str string
err = cn.Take(&str, "any", func(v interface{}) error { err = cn.Take(&str, "any", func(v any) error {
*v.(*string) = "value" *v.(*string) = "value"
return nil return nil
}) })
@@ -164,7 +167,7 @@ func TestCacheNode_TakeBadRedis(t *testing.T) {
cn := NewNode(redis.New(r.Addr()), syncx.NewSingleFlight(), NewStat("any"), cn := NewNode(redis.New(r.Addr()), syncx.NewSingleFlight(), NewStat("any"),
errTestNotFound, WithExpiry(time.Second), WithNotFoundExpiry(time.Second)) errTestNotFound, WithExpiry(time.Second), WithNotFoundExpiry(time.Second))
var str string var str string
assert.Error(t, cn.Take(&str, "any", func(v interface{}) error { assert.Error(t, cn.Take(&str, "any", func(v any) error {
*v.(*string) = "value" *v.(*string) = "value"
return nil return nil
})) }))
@@ -185,7 +188,7 @@ func TestCacheNode_TakeNotFound(t *testing.T) {
errNotFound: errTestNotFound, errNotFound: errTestNotFound,
} }
var str string var str string
err = cn.Take(&str, "any", func(v interface{}) error { err = cn.Take(&str, "any", func(v any) error {
return errTestNotFound return errTestNotFound
}) })
assert.True(t, cn.IsNotFound(err)) assert.True(t, cn.IsNotFound(err))
@@ -195,7 +198,7 @@ func TestCacheNode_TakeNotFound(t *testing.T) {
assert.Equal(t, `*`, val) assert.Equal(t, `*`, val)
store.Set("any", "*") store.Set("any", "*")
err = cn.Take(&str, "any", func(v interface{}) error { err = cn.Take(&str, "any", func(v any) error {
return nil return nil
}) })
assert.True(t, cn.IsNotFound(err)) assert.True(t, cn.IsNotFound(err))
@@ -203,12 +206,41 @@ func TestCacheNode_TakeNotFound(t *testing.T) {
store.Del("any") store.Del("any")
errDummy := errors.New("dummy") errDummy := errors.New("dummy")
err = cn.Take(&str, "any", func(v interface{}) error { err = cn.Take(&str, "any", func(v any) error {
return errDummy return errDummy
}) })
assert.Equal(t, errDummy, err) assert.Equal(t, errDummy, err)
} }
func TestCacheNode_TakeNotFoundButChangedByOthers(t *testing.T) {
store, clean, err := redistest.CreateRedis()
assert.NoError(t, err)
defer clean()
cn := cacheNode{
rds: store,
r: rand.New(rand.NewSource(time.Now().UnixNano())),
barrier: syncx.NewSingleFlight(),
lock: new(sync.Mutex),
unstableExpiry: mathx.NewUnstable(expiryDeviation),
stat: NewStat("any"),
errNotFound: errTestNotFound,
}
var str string
err = cn.Take(&str, "any", func(v any) error {
store.Set("any", "foo")
return errTestNotFound
})
assert.True(t, cn.IsNotFound(err))
val, err := store.Get("any")
if assert.NoError(t, err) {
assert.Equal(t, "foo", val)
}
assert.True(t, cn.IsNotFound(cn.Get("any", &str)))
}
func TestCacheNode_TakeWithExpire(t *testing.T) { func TestCacheNode_TakeWithExpire(t *testing.T) {
store, clean, err := redistest.CreateRedis() store, clean, err := redistest.CreateRedis()
assert.Nil(t, err) assert.Nil(t, err)
@@ -224,7 +256,7 @@ func TestCacheNode_TakeWithExpire(t *testing.T) {
errNotFound: errors.New("any"), errNotFound: errors.New("any"),
} }
var str string var str string
err = cn.TakeWithExpire(&str, "any", func(v interface{}, expire time.Duration) error { err = cn.TakeWithExpire(&str, "any", func(v any, expire time.Duration) error {
*v.(*string) = "value" *v.(*string) = "value"
return nil return nil
}) })
@@ -274,7 +306,7 @@ func TestCacheValueWithBigInt(t *testing.T) {
) )
assert.Nil(t, cn.Set(key, value)) assert.Nil(t, cn.Set(key, value))
var val interface{} var val any
assert.Nil(t, cn.Get(key, &val)) assert.Nil(t, cn.Get(key, &val))
assert.Equal(t, strconv.FormatInt(value, 10), fmt.Sprintf("%v", val)) assert.Equal(t, strconv.FormatInt(value, 10), fmt.Sprintf("%v", val))
} }

View File

@@ -48,7 +48,7 @@ func AddCleanTask(task func() error, keys ...string) {
}, time.Second) }, time.Second)
} }
func clean(key, value interface{}) { func clean(key, value any) {
taskRunner.Schedule(func() { taskRunner.Schedule(func() {
dt := value.(delayTask) dt := value.(delayTask)
err := dt.task() err := dt.task()

View File

@@ -5,6 +5,7 @@ import (
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/proc"
) )
func TestNextDelay(t *testing.T) { func TestNextDelay(t *testing.T) {
@@ -51,6 +52,7 @@ func TestNextDelay(t *testing.T) {
next, ok := nextDelay(test.input) next, ok := nextDelay(test.input)
assert.Equal(t, test.ok, ok) assert.Equal(t, test.ok, ok)
assert.Equal(t, test.output, next) assert.Equal(t, test.output, next)
proc.Shutdown()
}) })
} }
} }

View File

@@ -1,14 +0,0 @@
package clickhouse
import (
// imports the driver, don't remove this comment, golint requires.
_ "github.com/ClickHouse/clickhouse-go/v2"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
const clickHouseDriverName = "clickhouse"
// New returns a clickhouse connection.
func New(datasource string, opts ...sqlx.SqlOption) sqlx.SqlConn {
return sqlx.NewSqlConn(clickHouseDriverName, datasource, opts...)
}

View File

@@ -1,11 +0,0 @@
package clickhouse
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestClickHouse(t *testing.T) {
assert.NotNil(t, New("clickhouse"))
}

Some files were not shown because too many files have changed in this diff Show More